Class: Tina4::Drivers::SqliteDriver

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/drivers/sqlite_driver.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



6
7
8
# File 'lib/tina4/drivers/sqlite_driver.rb', line 6

def connection
  @connection
end

Class Method Details

.resolve_path(connection_string) ⇒ Object

Resolve a SQLite URL / path against the project root (cwd).

Convention (matches tina4-python, tina4-php, tina4-nodejs):

sqlite::memory:              → :memory:
sqlite:///:memory:           → :memory:
sqlite:///app.db             → {cwd}/app.db  (relative)
sqlite:///data/app.db        → {cwd}/data/app.db  (relative; auto-mkdir under cwd)
sqlite:////var/data/app.db   → /var/data/app.db  (absolute; no auto-mkdir)
sqlite:///C:/Users/app.db    → C:/Users/app.db  (Windows absolute)

Never mkdir outside cwd — that was the root cause of the “Read-only file system: ‘/data’” crash on macOS.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/tina4/drivers/sqlite_driver.rb', line 30

def self.resolve_path(connection_string)
  return ":memory:" if connection_string == "sqlite::memory:" || connection_string == "sqlite:///:memory:"

  # Strip the scheme + up to three slashes, preserving a potential fourth
  # slash (absolute) or drive letter.
  raw = connection_string.sub(/^sqlite:\/\/\//, "").sub(/^sqlite:\/\//, "").sub(/^sqlite:/, "")
  return ":memory:" if raw == ":memory:"

  is_windows_abs = raw.match?(/^[A-Za-z]:[\/\\]/)
  is_unix_abs    = raw.start_with?("/")

  if is_windows_abs || is_unix_abs
    # Absolute — trust the user; don't auto-mkdir outside cwd.
    raw
  else
    # Relative — resolve under cwd; auto-mkdir parent dir.
    resolved = File.join(Dir.pwd, raw)
    parent = File.dirname(resolved)
    require "fileutils"
    FileUtils.mkdir_p(parent) unless File.directory?(parent)
    resolved
  end
end

Instance Method Details

#apply_limit(sql, limit, offset = 0) ⇒ Object



79
80
81
# File 'lib/tina4/drivers/sqlite_driver.rb', line 79

def apply_limit(sql, limit, offset = 0)
  "#{sql} LIMIT #{limit} OFFSET #{offset}"
end

#begin_transactionObject



83
84
85
# File 'lib/tina4/drivers/sqlite_driver.rb', line 83

def begin_transaction
  @connection.execute("BEGIN TRANSACTION")
end

#closeObject



54
55
56
# File 'lib/tina4/drivers/sqlite_driver.rb', line 54

def close
  @connection&.close
end

#columns(table_name) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/tina4/drivers/sqlite_driver.rb', line 100

def columns(table_name)
  rows = execute_query("PRAGMA table_info(#{table_name})")
  rows.map do |r|
    {
      name: r[:name],
      type: r[:type],
      nullable: r[:notnull] == 0,
      default: r[:dflt_value],
      primary_key: r[:pk] == 1
    }
  end
end

#commitObject



87
88
89
# File 'lib/tina4/drivers/sqlite_driver.rb', line 87

def commit
  @connection.execute("COMMIT")
end

#connect(connection_string, username: nil, password: nil) ⇒ Object



8
9
10
11
12
13
14
15
16
# File 'lib/tina4/drivers/sqlite_driver.rb', line 8

def connect(connection_string, username: nil, password: nil)
  require "sqlite3"
  db_path = self.class.resolve_path(connection_string)

  @connection = SQLite3::Database.new(db_path)
  @connection.results_as_hash = true
  @connection.execute("PRAGMA journal_mode=WAL")
  @connection.execute("PRAGMA foreign_keys=ON")
end

#execute(sql, params = []) ⇒ Object



63
64
65
# File 'lib/tina4/drivers/sqlite_driver.rb', line 63

def execute(sql, params = [])
  @connection.execute(sql, params)
end

#execute_query(sql, params = []) ⇒ Object



58
59
60
61
# File 'lib/tina4/drivers/sqlite_driver.rb', line 58

def execute_query(sql, params = [])
  results = @connection.execute(sql, params)
  results.map { |row| symbolize_keys(row) }
end

#last_insert_idObject



67
68
69
# File 'lib/tina4/drivers/sqlite_driver.rb', line 67

def last_insert_id
  @connection.last_insert_row_id
end

#placeholderObject



71
72
73
# File 'lib/tina4/drivers/sqlite_driver.rb', line 71

def placeholder
  "?"
end

#placeholders(count) ⇒ Object



75
76
77
# File 'lib/tina4/drivers/sqlite_driver.rb', line 75

def placeholders(count)
  (["?"] * count).join(", ")
end

#rollbackObject



91
92
93
# File 'lib/tina4/drivers/sqlite_driver.rb', line 91

def rollback
  @connection.execute("ROLLBACK")
end

#tablesObject



95
96
97
98
# File 'lib/tina4/drivers/sqlite_driver.rb', line 95

def tables
  rows = execute_query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
  rows.map { |r| r[:name] }
end