Class: FtsLite::Index

Inherits:
Object
  • Object
show all
Defined in:
lib/fts_lite/index.rb

Defined Under Namespace

Classes: RuntimeError

Constant Summary collapse

DEFAULT_TOKENIZER =
:bigram
DEFAULT_JURNAL_MODE =
"MEMORY"
DEFAULT_TEMP_STORE =
"MEMORY"
DEFAULT_CACHE_SIZE =
32000
DEFAULT_TIMEOUT =
10000
SQLITE_HAVE_FT4_REPLACE =
SQLite3.libversion >= 3007007

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, options = {}) ⇒ Index

Returns a new instance of Index.



21
22
23
24
25
26
27
# File 'lib/fts_lite/index.rb', line 21

def initialize(path, options = {})
  @db = SQLite3::Database.new(path)
  @table_name = options[:table_name] || "fts_lite"
  create_table!(options)
  set_db_param(options)
  @tokenizer = Tokenizer.create(options[:tokenizer] || DEFAULT_TOKENIZER)
end

Class Method Details

.have_ft4_replaceObject



12
13
14
# File 'lib/fts_lite/index.rb', line 12

def self.have_ft4_replace
  SQLITE_HAVE_FT4_REPLACE
end

.open(path, options = {}) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/fts_lite/index.rb', line 28

def self.open(path, options = {})
  if (block_given?)
    index = Index.new(path, options)
    begin
      yield(index)
    ensure
      index.close
    end
  else
    Index.new(path, options)
  end
end

.sqlite3_versionObject



15
16
17
# File 'lib/fts_lite/index.rb', line 15

def self.sqlite3_version
  SQLite3.libversion
end

Instance Method Details

#closeObject



55
56
57
# File 'lib/fts_lite/index.rb', line 55

def close
  @db.close
end

#countObject



134
135
136
# File 'lib/fts_lite/index.rb', line 134

def count
  @db.execute("SELECT COUNT(*) FROM #{@table_name} ;").first.first
end

#delete(docid) ⇒ Object



84
85
86
# File 'lib/fts_lite/index.rb', line 84

def delete(docid)
  @db.execute("DELETE FROM #{@table_name} WHERE docid = ?;", [docid])
end

#delete_allObject



137
138
139
# File 'lib/fts_lite/index.rb', line 137

def delete_all
  @db.execute("DELETE FROM #{@table_name} ;")
end

#drop_table!Object



140
141
142
143
144
# File 'lib/fts_lite/index.rb', line 140

def drop_table!
  if (table_exist?)
    @db.execute("DROP TABLE #{@table_name};")
  end
end

#search(text, options = {}) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/fts_lite/index.rb', line 87

def search(text, options = {})
  options ||= {}
  limit = options[:limit]
  order = nil
  gt = nil
  lt = nil
  gte = nil
  lte = nil
  if (options[:order])
    case options[:order].to_sym
    when :desc
      order = :desc
    when :asc
      order = :asc
    end
  end
  if (options[:range])
    gt = options[:range][:gt]
    lt = options[:range][:lt]
    gte = options[:range][:gte]
    lte = options[:range][:lte]
  end
  sql = "SELECT docid FROM #{@table_name} WHERE text MATCH ?"
  if gt
    sql += " AND sort_value > ? "
  end
  if lt
    sql += " AND sort_value < ? "
  end
  if gte
    sql += " AND sort_value >= ? "
  end
  if lte
    sql += " AND sort_value <= ? "
  end
  if (order)
    sql += sprintf(" ORDER BY sort_value %s", order == :desc ? "DESC" : "ASC")
  else
    sql += sprintf(" ORDER BY docid ASC")
  end
  if (limit)
    sql += sprintf(" LIMIT %d", limit)
  end
  sql += ";"
  conditions = [gt, lt, gte, lte].reject{|v| v.nil?}.map{|v| sql_value(v)}
  @db.execute(sql, [@tokenizer.query(text, options), conditions].flatten).flatten
end

#set(docid, text, sort_value = nil) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/fts_lite/index.rb', line 66

def set(docid, text, sort_value = nil)
  if (SQLITE_HAVE_FT4_REPLACE)
    @db.execute("INSERT OR REPLACE INTO #{@table_name} (docid, text, sort_value) VALUES(?, ?, ?);",
                [docid, @tokenizer.vector(text), sql_value(sort_value)])
  else
    begin
      @db.execute("INSERT INTO #{@table_name} (docid, text, sort_value) VALUES(?, ?, ?);",
                  [docid, @tokenizer.vector(text), sql_value(sort_value)])
    rescue SQLite3::ConstraintException
      @db.execute("UPDATE #{@table_name} SET text = ?, sort_value = ? WHERE docid = ?;",
                  [@tokenizer.vector(text), sql_value(sort_value), docid])
    end
  end
end

#sql_value(x) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/fts_lite/index.rb', line 41

def sql_value(x)
  if x.nil?
    x
  elsif x.is_a?(DateTime)
    x.iso8601
  elsif x.is_a?(Date)
    x.iso8601
  elsif x.is_a?(Time)
    x.to_datetime.iso8601
  else
    x
  end
end

#tokenize(text) ⇒ Object



58
59
60
# File 'lib/fts_lite/index.rb', line 58

def tokenize(text)
  @tokenizer.vector(text).split(" ")
end

#transaction(&block) ⇒ Object



61
62
63
64
65
# File 'lib/fts_lite/index.rb', line 61

def transaction(&block)
  @db.transaction do
    block.call
  end
end

#update_sort_value(docid, sort_value) ⇒ Object



80
81
82
83
# File 'lib/fts_lite/index.rb', line 80

def update_sort_value(docid, sort_value)
  @db.execute("UPDATE #{@table_name} SET sort_value = ? WHERE docid = ?;",
              [sql_value(sort_value), docid])
end