Module: BetterAuth::Sinatra::Migration

Defined in:
lib/better_auth/sinatra/migration.rb

Defined Under Namespace

Classes: UnsupportedAdapterError

Constant Summary collapse

DEFAULT_MIGRATIONS_PATH =
"db/better_auth/migrate"

Class Method Summary collapse

Class Method Details

.applied_migrations(connection, dialect) ⇒ Object



81
82
83
84
85
86
# File 'lib/better_auth/sinatra/migration.rb', line 81

def applied_migrations(connection, dialect)
  rows = execute_sql(connection, "SELECT #{quote("version", dialect)} FROM #{quote("better_auth_schema_migrations", dialect)};")
  Array(rows).map { |row| row["version"] || row[:version] }
rescue
  []
end

.auth_for(value) ⇒ Object



61
62
63
64
65
# File 'lib/better_auth/sinatra/migration.rb', line 61

def auth_for(value)
  return value if value.is_a?(BetterAuth::Auth)

  BetterAuth.auth(value)
end

.configuration_for(options) ⇒ Object



54
55
56
57
58
59
# File 'lib/better_auth/sinatra/migration.rb', line 54

def configuration_for(options)
  return options.options if options.is_a?(BetterAuth::Auth)
  return options if options.is_a?(BetterAuth::Configuration)

  BetterAuth::Configuration.new(options)
end

.ensure_schema_migrations!(connection, dialect) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/better_auth/sinatra/migration.rb', line 67

def ensure_schema_migrations!(connection, dialect)
  sql = case dialect
  when :postgres, :sqlite
    %(CREATE TABLE IF NOT EXISTS #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} text PRIMARY KEY);)
  when :mysql
    %(CREATE TABLE IF NOT EXISTS #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} varchar(191) PRIMARY KEY) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;)
  when :mssql
    %(IF OBJECT_ID(N'#{quote("better_auth_schema_migrations", dialect)}', N'U') IS NULL CREATE TABLE #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)} varchar(255) PRIMARY KEY);)
  else
    raise UnsupportedAdapterError, "Unsupported SQL dialect for better_auth-sinatra migrations: #{dialect}"
  end
  execute_sql(connection, sql)
end

.execute_sql(connection, sql) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/better_auth/sinatra/migration.rb', line 93

def execute_sql(connection, sql)
  statements(sql).each_with_object([]) do |statement, results|
    result =
      if connection.respond_to?(:exec)
        connection.exec(statement)
      elsif connection.respond_to?(:execute)
        connection.execute(statement)
      elsif connection.respond_to?(:query)
        connection.query(statement)
      else
        raise UnsupportedAdapterError, "SQL connection does not support exec, execute, or query"
      end
    results.concat(result.to_a) if result.respond_to?(:to_a)
  end
end

.generate(options, dialect:, migrations_path: DEFAULT_MIGRATIONS_PATH, timestamp: Time.now.utc.strftime("%Y%m%d%H%M%S")) ⇒ Object



26
27
28
29
30
31
32
33
# File 'lib/better_auth/sinatra/migration.rb', line 26

def generate(options, dialect:, migrations_path: DEFAULT_MIGRATIONS_PATH, timestamp: Time.now.utc.strftime("%Y%m%d%H%M%S"))
  FileUtils.mkdir_p(migrations_path)
  path = File.join(migrations_path, "#{timestamp}_create_better_auth_tables.sql")
  return path if File.exist?(path)

  File.write(path, render(options, dialect: dialect))
  path
end

.literal(value) ⇒ Object



117
118
119
# File 'lib/better_auth/sinatra/migration.rb', line 117

def literal(value)
  "'#{value.to_s.gsub("'", "''")}'"
end

.migrate(auth_or_options, migrations_path: DEFAULT_MIGRATIONS_PATH) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/better_auth/sinatra/migration.rb', line 35

def migrate(auth_or_options, migrations_path: DEFAULT_MIGRATIONS_PATH)
  auth = auth_for(auth_or_options)
  adapter = auth.context.adapter
  unless adapter.respond_to?(:dialect) && adapter.respond_to?(:connection)
    raise UnsupportedAdapterError, "better_auth-sinatra migrations require core SQL adapters with connection and dialect support"
  end

  connection = adapter.connection
  dialect = adapter.dialect.to_sym
  files = Dir[File.join(migrations_path, "*.sql")].sort
  ensure_schema_migrations!(connection, dialect)
  applied = applied_migrations(connection, dialect)

  files.reject { |file| applied.include?(File.basename(file)) }.each do |file|
    execute_sql(connection, File.read(file))
    record_migration(connection, dialect, File.basename(file))
  end
end

.quote(identifier, dialect) ⇒ Object



113
114
115
# File 'lib/better_auth/sinatra/migration.rb', line 113

def quote(identifier, dialect)
  BetterAuth::Schema::SQL.quote(identifier, dialect)
end

.record_migration(connection, dialect, version) ⇒ Object



88
89
90
91
# File 'lib/better_auth/sinatra/migration.rb', line 88

def record_migration(connection, dialect, version)
  sql = "INSERT INTO #{quote("better_auth_schema_migrations", dialect)} (#{quote("version", dialect)}) VALUES (#{literal(version)});"
  execute_sql(connection, sql)
end

.render(options, dialect:) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/better_auth/sinatra/migration.rb', line 14

def render(options, dialect:)
  config = configuration_for(options)
  statements = BetterAuth::Schema::SQL.create_statements(config, dialect: dialect)
  [
    "-- Generated by better_auth-sinatra",
    "-- Dialect: #{dialect}",
    "",
    statements.join("\n\n"),
    ""
  ].join("\n")
end

.statements(sql) ⇒ Object



109
110
111
# File 'lib/better_auth/sinatra/migration.rb', line 109

def statements(sql)
  sql.split(/;\s*$/).map(&:strip).reject(&:empty?)
end