Class: SlugDB::SQLite3

Inherits:
Object
  • Object
show all
Defined in:
lib/slugdb/sqlite3.rb,
lib/slugdb/sqlite3/version.rb

Overview

SlugDB backed by SQLite3

Constant Summary collapse

VERSION =
'0.1.0'

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ SQLite3

rubocop:disable Metrics/MethodLength



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 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

Instance Method Details

#add_index(name:, pk:, sk:, reindex: false) ⇒ Object

rubocop:disable Metrics/MethodLength,Naming/MethodParameterName



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 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:, **_) ⇒ Object

rubocop:disable Naming/MethodParameterName



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# 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:, **_) ⇒ Object

rubocop:disable Naming/MethodParameterName



82
83
84
85
86
87
# 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_indexesObject



37
38
39
40
# 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_partitionsObject



33
34
35
# 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) ⇒ Object

rubocop:disable Metrics/AbcSize,Naming/MethodParameterName



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# 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) ⇒ Object

rubocop:disable Naming/MethodParameterName



124
125
126
127
128
129
130
131
132
133
134
135
136
# 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) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
# 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