class SlugDB::SQLite3
Constants
- VERSION
Public Class Methods
new(file)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 10 def initialize(file) # rubocop:disable Metrics/MethodLength @sdb = ::SQLite3::Database.new(file) @sdb.execute( <<~SQL CREATE TABLE IF NOT EXISTS main( pk varchar(2048) NOT NULL, sk varchar(1024) NOT NULL, item varchar(409600) NOT NULL, PRIMARY KEY(pk, sk) ) SQL ) @sdb.execute( <<~SQL CREATE TABLE IF NOT EXISTS indexes( name varchar(255) NOT NULL, schema varchar(4096) NOT NULL, PRIMARY KEY(name) ) SQL ) end
Public Instance Methods
add_index(name:, pk:, sk:, reindex: false)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 42 def add_index(name:, pk:, sk:, reindex: false) # rubocop:disable Metrics/MethodLength,Naming/MethodParameterName index = { name => { pk: pk, sk: sk } } if @sdb.execute('SELECT name FROM indexes WHERE name = ?', name).empty? @sdb.execute( <<~SQL CREATE TABLE IF NOT EXISTS index_#{name}( ipk varchar(2048) NOT NULL, isk varchar(1024) NOT NULL, pk varchar(2048) NOT NULL, sk varchar(1024) NOT NULL, item varchar(409600) NOT NULL, PRIMARY KEY(ipk, isk, pk, sk) ) SQL ) @sdb.execute( 'INSERT INTO indexes (name, schema) VALUES (?, ?)', [name, to_raw(pk: pk, sk: sk)] ) end reindex!(index) if reindex index end
delete_item(pk:, sk:, **_)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 108 def delete_item(pk:, sk:, **_) # rubocop:disable Naming/MethodParameterName item = get_item(pk: pk, sk: sk) return if item.nil? indexes = list_indexes @sdb.execute('BEGIN TRANSACTION') @sdb.execute('DELETE FROM main WHERE pk = ? AND sk = ?', [pk, sk]) index_delete_statements(indexes, item).each { |s, v| @sdb.execute(s, v) } @sdb.execute('COMMIT TRANSACTION') item rescue SQLite3::SQLException => e @sdb.execute('ABORT TRANSACTION') raise e end
get_item(pk:, sk:, **_)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 82 def get_item(pk:, sk:, **_) # rubocop:disable Naming/MethodParameterName @sdb.execute( 'SELECT item FROM main WHERE pk = ? AND sk = ?', [pk, sk] ).flatten.map(&method(:to_item)).first end
list_indexes()
click to toggle source
# File lib/slugdb/sqlite3.rb, line 37 def list_indexes @sdb.execute('SELECT * FROM indexes') .reduce({}) { |memo, (name, schema)| memo.merge(name => to_item(schema)) } end
list_partitions()
click to toggle source
# File lib/slugdb/sqlite3.rb, line 33 def list_partitions @sdb.execute('SELECT pk FROM main').map(&:first).uniq end
put_item(pk:, sk:, **attributes)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 89 def put_item(pk:, sk:, **attributes) # rubocop:disable Metrics/AbcSize,Naming/MethodParameterName new_item = attributes.merge(pk: pk, sk: sk) raw_item = to_raw(new_item) old_item = get_item(**new_item) indexes = list_indexes @sdb.execute('BEGIN TRANSACTION') @sdb.execute('DELETE FROM main WHERE pk = ? AND sk = ?', [pk, sk]) index_delete_statements(indexes, old_item).each { |s, v| @sdb.execute(s, v) } index_insert_statements(indexes, new_item, raw_item).each { |s, v| @sdb.execute(s, v) } @sdb.execute('INSERT INTO main (pk, sk, item) VALUES (?, ?, ?)', [pk, sk, raw_item]) @sdb.execute('COMMIT TRANSACTION') new_item rescue SQLite3::SQLException => e @sdb.execute('ABORT TRANSACTION') raise e end
query(pk:, index: 'main', select: nil, filter: nil)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 124 def query(pk:, index: 'main', select: nil, filter: nil) # rubocop:disable Naming/MethodParameterName results = if index == 'main' raw_query('SELECT sk, item FROM main WHERE pk = ?', [pk]) else raw_query("SELECT isk, item FROM index_#{index} WHERE ipk = ?", [pk]) end results = results.select { |sk,| select[sk] } if select results = results.filter { |_, item| filter[item] } if filter results.map(&:last) end
reindex!(index)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 69 def reindex!(index) @sdb.execute('SELECT item FROM main').each do |raw_item,| item = to_item(raw_item) @sdb.execute('BEGIN TRANSACTION') index_delete_statements(index, item).each { |s, v| @sdb.execute(s, v) } index_insert_statements(index, item, raw_item).each { |s, v| @sdb.execute(s, v) } @sdb.execute('COMMIT TRANSACTION') end rescue ::SQLite3::SQLException => e @sdb.execute('ABORT TRANSACTION') raise e end
Private Instance Methods
index_delete_statements(indexes, item)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 148 def index_delete_statements(indexes, item) indexes.map do |name, schema| next if item.nil? [ "DELETE FROM index_#{name} WHERE #{schema[:pk]} = ? AND #{schema[:sk]} = ?", [item[schema[:pk]], item[schema[:sk]]] ] end.compact end
index_insert_statements(indexes, item, raw_item)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 159 def index_insert_statements(indexes, item, raw_item) indexes.map do |name, schema| next unless item.key?(schema[:pk]) && item.key?(schema[:sk]) [ "INSERT INTO index_#{name} (ipk, isk, pk, sk, item) VALUES(?, ?, ?, ?, ?)", [item[schema[:pk]], item[schema[:sk]], item[:pk], item[:sk], raw_item] ] end.compact end
raw_query(statement, values) { |sk, to_item(raw_item)| ... }
click to toggle source
# File lib/slugdb/sqlite3.rb, line 170 def raw_query(statement, values) return enum_for(:raw_query, statement, values) unless block_given? @sdb.execute(statement, values).each { |sk, raw_item| yield [sk, to_item(raw_item)] } end
to_item(raw)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 144 def to_item(raw) Marshal.load(raw) # rubocop:disable Security/MarshalLoad end
to_raw(item)
click to toggle source
# File lib/slugdb/sqlite3.rb, line 140 def to_raw(item) Marshal.dump(item) end