Class: Jimmu::Database
- Inherits:
-
Object
- Object
- Jimmu::Database
- Defined in:
- lib/jimmu.rb
Overview
A small SQLite wrapper exposing the query / exec / transaction API described in the Jimmu spec. A single Database instance may be shared across the many request-handling threads the server spawns; all access to the underlying sqlite3 connection handle is serialized through a re-entrant Monitor so that (a) concurrent requests never touch the C-level handle at the same time and (b) a block passed to #transaction can itself call #query / #exec on the same thread without deadlocking.
Constant Summary collapse
- SQLITE_OK =
0- SQLITE_ROW =
100- SQLITE_DONE =
101- SQLITE_INTEGER =
1- SQLITE_FLOAT =
2- SQLITE_TEXT =
3- SQLITE_BLOB =
4- SQLITE_NULL =
5- SQLITE_TRANSIENT =
Fiddle::Pointer.new(-1)
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Instance Method Summary collapse
- #close ⇒ Object
-
#exec(sql, *binds) ⇒ Object
Run an INSERT / UPDATE / DELETE / DDL statement.
-
#initialize(path) ⇒ Database
constructor
A new instance of Database.
-
#last_insert_rowid ⇒ Object
The rowid of the most recent successful INSERT on this connection.
-
#query(sql, *binds) ⇒ Object
Run a SELECT (or any statement that returns rows) and return an Array of Hashes, keyed by column name (as Symbols).
-
#transaction ⇒ Object
Wrap a block in BEGIN / COMMIT.
Constructor Details
#initialize(path) ⇒ Database
Returns a new instance of Database.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/jimmu.rb', line 208 def initialize(path) unless SQLite3FFI::LOADED raise DatabaseError, "Could not locate the SQLite3 shared library on this system " \ "(looked for: #{SQLite3FFI::LIB_CANDIDATES.join(', ')}). " \ "Install SQLite3 (e.g. `apt install libsqlite3-0`, `brew install sqlite3`); " \ "it ships with macOS by default, and Windows needs sqlite3.dll on the PATH." end @path = path dir = File.dirname(path) FileUtils.mkdir_p(dir) unless dir == '.' || Dir.exist?(dir) @lock = Monitor.new dbptr = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP) rc = SQLite3FFI.sqlite3_open(path.to_s, dbptr) @db = dbptr.ptr if rc != SQLITE_OK raise DatabaseError, "Could not open database at #{path.inspect} (sqlite3_open returned #{rc})" end SQLite3FFI.sqlite3_busy_timeout(@db, 5000) end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
206 207 208 |
# File 'lib/jimmu.rb', line 206 def path @path end |
Instance Method Details
#close ⇒ Object
279 280 281 282 283 284 285 |
# File 'lib/jimmu.rb', line 279 def close @lock.synchronize do next if @closed SQLite3FFI.sqlite3_close(@db) @closed = true end end |
#exec(sql, *binds) ⇒ Object
Run an INSERT / UPDATE / DELETE / DDL statement. Returns the number of rows changed by the statement (via sqlite3_changes).
db.exec("INSERT INTO users(name) VALUES (?)", "Yamato")
244 245 246 |
# File 'lib/jimmu.rb', line 244 def exec(sql, *binds) @lock.synchronize { run_exec(sql, binds) } end |
#last_insert_rowid ⇒ Object
The rowid of the most recent successful INSERT on this connection.
275 276 277 |
# File 'lib/jimmu.rb', line 275 def last_insert_rowid @lock.synchronize { SQLite3FFI.sqlite3_last_insert_rowid(@db) } end |
#query(sql, *binds) ⇒ Object
Run a SELECT (or any statement that returns rows) and return an Array of Hashes, keyed by column name (as Symbols).
db.query("SELECT * FROM users")
db.query("SELECT * FROM users WHERE id = ?", id)
236 237 238 |
# File 'lib/jimmu.rb', line 236 def query(sql, *binds) @lock.synchronize { run_query(sql, binds) } end |
#transaction ⇒ Object
Wrap a block in BEGIN / COMMIT. If the block raises, the transaction is rolled back and the error re-raised.
db.transaction do
db.exec(...)
db.exec(...)
end
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/jimmu.rb', line 255 def transaction @lock.synchronize do run_exec('BEGIN', []) begin result = yield run_exec('COMMIT', []) result rescue Exception => e begin run_exec('ROLLBACK', []) rescue Exception nil # the original error is more useful than a rollback failure end raise e end end end |