litestack 0.4.1 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.standard.yml +3 -0
- data/BENCHMARKS.md +23 -7
- data/CHANGELOG.md +35 -0
- data/Gemfile +1 -7
- data/README.md +124 -6
- data/ROADMAP.md +45 -0
- data/Rakefile +3 -1
- data/WHYLITESTACK.md +1 -1
- data/assets/litecache_metrics.png +0 -0
- data/assets/litedb_metrics.png +0 -0
- data/assets/litemetric_logo_teal.png +0 -0
- data/assets/litesearch_logo_teal.png +0 -0
- data/bench/bench.rb +17 -10
- data/bench/bench_cache_rails.rb +45 -14
- data/bench/bench_cache_raw.rb +44 -28
- data/bench/bench_jobs_rails.rb +18 -12
- data/bench/bench_jobs_raw.rb +17 -10
- data/bench/bench_queue.rb +4 -6
- data/bench/rails_job.rb +5 -7
- data/bench/skjob.rb +4 -4
- data/bench/uljob.rb +6 -6
- data/bin/liteboard +2 -1
- data/lib/action_cable/subscription_adapter/litecable.rb +5 -8
- data/lib/active_job/queue_adapters/litejob_adapter.rb +6 -8
- data/lib/active_record/connection_adapters/litedb_adapter.rb +72 -84
- data/lib/active_support/cache/litecache.rb +61 -41
- data/lib/generators/litestack/install/install_generator.rb +3 -3
- data/lib/generators/litestack/install/templates/cable.yml +0 -3
- data/lib/generators/litestack/install/templates/database.yml +7 -1
- data/lib/litestack/liteboard/liteboard.rb +269 -149
- data/lib/litestack/litecable.rb +41 -37
- data/lib/litestack/litecable.sql.yml +22 -11
- data/lib/litestack/litecache.rb +118 -93
- data/lib/litestack/litecache.sql.yml +83 -22
- data/lib/litestack/litecache.yml +1 -1
- data/lib/litestack/litedb.rb +35 -40
- data/lib/litestack/litejob.rb +30 -29
- data/lib/litestack/litejobqueue.rb +63 -65
- data/lib/litestack/litemetric.rb +80 -92
- data/lib/litestack/litemetric.sql.yml +244 -234
- data/lib/litestack/litemetric_collector.sql.yml +38 -41
- data/lib/litestack/litequeue.rb +39 -41
- data/lib/litestack/litequeue.sql.yml +39 -31
- data/lib/litestack/litescheduler.rb +24 -18
- data/lib/litestack/litesearch/index.rb +93 -63
- data/lib/litestack/litesearch/model.rb +66 -65
- data/lib/litestack/litesearch/schema.rb +53 -56
- data/lib/litestack/litesearch/schema_adapters/backed_adapter.rb +46 -50
- data/lib/litestack/litesearch/schema_adapters/basic_adapter.rb +44 -35
- data/lib/litestack/litesearch/schema_adapters/contentless_adapter.rb +3 -6
- data/lib/litestack/litesearch/schema_adapters/standalone_adapter.rb +7 -9
- data/lib/litestack/litesearch/schema_adapters.rb +4 -9
- data/lib/litestack/litesearch.rb +6 -9
- data/lib/litestack/litesupport.rb +78 -87
- data/lib/litestack/railtie.rb +1 -1
- data/lib/litestack/version.rb +2 -2
- data/lib/litestack.rb +6 -4
- data/lib/railties/rails/commands/dbconsole.rb +16 -20
- data/lib/sequel/adapters/litedb.rb +16 -21
- data/lib/sequel/adapters/shared/litedb.rb +168 -168
- data/scripts/build_metrics.rb +91 -0
- data/scripts/test_cable.rb +30 -0
- data/scripts/test_job_retry.rb +33 -0
- data/scripts/test_metrics.rb +60 -0
- data/template.rb +2 -2
- metadata +115 -7
@@ -1,8 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require_relative
|
1
|
+
require "oj"
|
2
|
+
require_relative "./schema"
|
3
3
|
|
4
4
|
class Litesearch::Index
|
5
|
-
|
6
5
|
DEFAULT_SEARCH_OPTIONS = {limit: 25, offset: 0}
|
7
6
|
|
8
7
|
def initialize(db, name)
|
@@ -17,14 +16,14 @@ class Litesearch::Index
|
|
17
16
|
# if they differ in tokenizer then rebuild if auto-rebuild is on (error otherwise)
|
18
17
|
# if they differ in both then update the structure and rebuild if auto-rebuild is on (error otherwise)
|
19
18
|
load_index(name) if exists?(name)
|
20
|
-
|
19
|
+
|
21
20
|
if block_given?
|
22
21
|
schema = Litesearch::Schema.new
|
23
22
|
schema.schema[:name] = name
|
24
23
|
yield schema
|
25
24
|
schema.post_init
|
26
25
|
# now that we have a schema object we need to check if we need to create or modify and existing index
|
27
|
-
@db.
|
26
|
+
if @db.transaction_active?
|
28
27
|
if exists?(name)
|
29
28
|
load_index(name)
|
30
29
|
do_modify(schema)
|
@@ -32,111 +31,141 @@ class Litesearch::Index
|
|
32
31
|
do_create(schema)
|
33
32
|
end
|
34
33
|
prepare_statements
|
35
|
-
end
|
36
|
-
else
|
37
|
-
if exists?(name)
|
38
|
-
# an index already exists, load it from the database and return the index instance to the caller
|
39
|
-
load_index(name)
|
40
|
-
prepare_statements
|
41
34
|
else
|
42
|
-
|
35
|
+
@db.transaction(:immediate) do
|
36
|
+
if exists?(name)
|
37
|
+
load_index(name)
|
38
|
+
do_modify(schema)
|
39
|
+
else
|
40
|
+
do_create(schema)
|
41
|
+
end
|
42
|
+
prepare_statements
|
43
|
+
end
|
43
44
|
end
|
45
|
+
elsif exists?(name)
|
46
|
+
load_index(name)
|
47
|
+
prepare_statements
|
48
|
+
# an index already exists, load it from the database and return the index instance to the caller
|
49
|
+
else
|
50
|
+
raise "index does not exist and no schema was supplied"
|
44
51
|
end
|
45
52
|
end
|
46
|
-
|
53
|
+
|
47
54
|
def load_index(name)
|
48
55
|
# we cannot use get_config_value here since the schema object is not created yet, should we allow something here?
|
49
|
-
@schema =
|
56
|
+
@schema = begin
|
57
|
+
Litesearch::Schema.new(Oj.load(@db.get_first_value("SELECT v from #{name}_config where k = ?", :litesearch_schema.to_s)))
|
58
|
+
rescue
|
59
|
+
nil
|
60
|
+
end
|
50
61
|
raise "index configuration not found, either corrupted or not a litesearch index!" if @schema.nil?
|
51
62
|
self
|
52
63
|
end
|
53
|
-
|
64
|
+
|
54
65
|
def modify
|
55
66
|
schema = Litesearch::Schema.new
|
56
67
|
yield schema
|
57
68
|
schema.schema[:name] = @schema.schema[:name]
|
58
69
|
do_modify(schema)
|
59
70
|
end
|
60
|
-
|
71
|
+
|
61
72
|
def rebuild!
|
62
|
-
@db.
|
63
|
-
|
73
|
+
if @db.transaction_active?
|
74
|
+
do_rebuild
|
75
|
+
else
|
76
|
+
@db.transaction(:immediate) { do_rebuild }
|
64
77
|
end
|
65
78
|
end
|
66
|
-
|
79
|
+
|
67
80
|
def add(document)
|
68
81
|
@stmts[:insert].execute!(document)
|
69
|
-
|
82
|
+
@db.last_insert_row_id
|
70
83
|
end
|
71
|
-
|
84
|
+
|
72
85
|
def remove(id)
|
73
86
|
@stmts[:delete].execute!(id)
|
74
87
|
end
|
75
|
-
|
88
|
+
|
76
89
|
def count(term = nil)
|
77
90
|
if term
|
78
91
|
@stmts[:count].execute!(term)[0][0]
|
79
92
|
else
|
80
|
-
@stmts[:count_all].execute!
|
93
|
+
@stmts[:count_all].execute![0][0]
|
81
94
|
end
|
82
95
|
end
|
83
|
-
|
96
|
+
|
84
97
|
# search options include
|
85
98
|
# limit: how many records to return
|
86
99
|
# offset: start from which record
|
87
100
|
def search(term, options = {})
|
88
|
-
result = []
|
89
101
|
options = DEFAULT_SEARCH_OPTIONS.merge(options)
|
90
102
|
rs = @stmts[:search].execute(term, options[:limit], options[:offset])
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
103
|
+
generate_results(rs)
|
104
|
+
end
|
105
|
+
|
106
|
+
def similar(id, limit=10)
|
107
|
+
# pp term = @db.execute(@schema.sql_for(:similarity_query), id)
|
108
|
+
if @schema.schema[:tokenizer] == :trigram
|
109
|
+
# just use the normal similarity approach for now
|
110
|
+
# need to recondisder that for trigram indexes later
|
111
|
+
rs = @stmts[:similar].execute(id, limit)
|
95
112
|
else
|
96
|
-
|
97
|
-
end
|
98
|
-
|
113
|
+
rs = @stmts[:similar].execute(id, limit)
|
114
|
+
end
|
115
|
+
generate_results(rs)
|
99
116
|
end
|
100
|
-
|
117
|
+
|
101
118
|
def clear!
|
102
119
|
@stmts[:delete_all].execute!(id)
|
103
120
|
end
|
104
|
-
|
121
|
+
|
105
122
|
def drop!
|
106
123
|
if @schema.get(:type) == :backed
|
107
124
|
@db.execute_batch(@schema.sql_for(:drop_primary_triggers))
|
108
|
-
if
|
125
|
+
if @schema.sql_for(:create_secondary_triggers)
|
109
126
|
@db.execute_batch(@schema.sql_for(:drop_secondary_triggers))
|
110
127
|
end
|
111
128
|
end
|
112
129
|
@db.execute(@schema.sql_for(:drop))
|
113
130
|
end
|
114
|
-
|
115
|
-
|
131
|
+
|
116
132
|
private
|
117
|
-
|
133
|
+
|
134
|
+
def generate_results(rs)
|
135
|
+
result = []
|
136
|
+
if @db.results_as_hash
|
137
|
+
rs.each_hash do |hash|
|
138
|
+
result << hash
|
139
|
+
end
|
140
|
+
else
|
141
|
+
result = rs.to_a
|
142
|
+
end
|
143
|
+
result
|
144
|
+
end
|
145
|
+
|
118
146
|
def exists?(name)
|
119
147
|
@db.get_first_value("SELECT count(*) FROM SQLITE_MASTER WHERE name = ? AND type = 'table' AND (sql like '%fts5%' OR sql like '%FTS5%')", name.to_s) == 1
|
120
148
|
end
|
121
149
|
|
122
150
|
def prepare_statements
|
123
|
-
stmt_names = [:insert, :delete, :delete_all, :drop, :count, :count_all, :search]
|
151
|
+
stmt_names = [:insert, :delete, :delete_all, :drop, :count, :count_all, :search, :similar]
|
124
152
|
stmt_names.each do |stmt_name|
|
125
153
|
@stmts[stmt_name] = @db.prepare(@schema.sql_for(stmt_name))
|
126
|
-
end
|
154
|
+
end
|
127
155
|
end
|
128
|
-
|
129
|
-
def do_create(schema)
|
130
|
-
@schema = schema
|
156
|
+
|
157
|
+
def do_create(schema)
|
158
|
+
@schema = schema
|
131
159
|
@schema.clean
|
132
160
|
# create index
|
133
161
|
@db.execute(schema.sql_for(:create_index, true))
|
162
|
+
@db.execute_batch(schema.sql_for(:create_vocab_tables))
|
134
163
|
# adjust ranking function
|
135
164
|
@db.execute(schema.sql_for(:ranks, true))
|
136
165
|
# create triggers (if any)
|
137
166
|
if @schema.get(:type) == :backed
|
138
167
|
@db.execute_batch(@schema.sql_for(:create_primary_triggers))
|
139
|
-
if secondary_triggers_sql = @schema.sql_for(:create_secondary_triggers)
|
168
|
+
if (secondary_triggers_sql = @schema.sql_for(:create_secondary_triggers))
|
140
169
|
@db.execute_batch(secondary_triggers_sql)
|
141
170
|
end
|
142
171
|
@db.execute(@schema.sql_for(:rebuild)) if @schema.get(:rebuild_on_create)
|
@@ -152,11 +181,11 @@ class Litesearch::Index
|
|
152
181
|
requires_schema_change = false
|
153
182
|
requires_trigger_change = false
|
154
183
|
requires_rebuild = false
|
155
|
-
if changes[:fields] || changes[:table] || changes[:tokenizer] || changes[:filter_column] || changes[:removed_fields_count] > 0# any change here will require a schema change
|
184
|
+
if changes[:fields] || changes[:table] || changes[:tokenizer] || changes[:filter_column] || changes[:removed_fields_count] > 0 # any change here will require a schema change
|
156
185
|
requires_schema_change = true
|
157
186
|
# only a change in tokenizer
|
158
187
|
requires_rebuild = changes[:tokenizer] || new_schema.get(:rebuild_on_modify)
|
159
|
-
requires_trigger_change = (changes[:table] || changes[:fields] || changes[:filter_column]) && @schema.get(:type) == :backed
|
188
|
+
requires_trigger_change = (changes[:table] || changes[:fields] || changes[:filter_column]) && @schema.get(:type) == :backed
|
160
189
|
end
|
161
190
|
if requires_schema_change
|
162
191
|
# 1. enable schema editing
|
@@ -169,12 +198,12 @@ class Litesearch::Index
|
|
169
198
|
@db.execute(new_schema.sql_for(:expand_data), changes[:extra_fields_count])
|
170
199
|
@db.execute(new_schema.sql_for(:expand_docsize), changes[:extra_fields_count])
|
171
200
|
@db.execute("PRAGMA WRITABLE_SCHEMA = RESET")
|
172
|
-
# need to reprepare statements
|
201
|
+
# need to reprepare statements
|
173
202
|
end
|
174
203
|
if requires_trigger_change
|
175
204
|
@db.execute_batch(new_schema.sql_for(:drop_primary_triggers))
|
176
205
|
@db.execute_batch(new_schema.sql_for(:create_primary_triggers))
|
177
|
-
if secondary_triggers_sql = new_schema.sql_for(:create_secondary_triggers)
|
206
|
+
if (secondary_triggers_sql = new_schema.sql_for(:create_secondary_triggers))
|
178
207
|
@db.execute_batch(new_schema.sql_for(:drop_secondary_triggers))
|
179
208
|
@db.execute_batch(secondary_triggers_sql)
|
180
209
|
end
|
@@ -183,48 +212,49 @@ class Litesearch::Index
|
|
183
212
|
@schema = new_schema
|
184
213
|
set_config_value(:litesearch_schema, @schema.schema)
|
185
214
|
prepare_statements
|
186
|
-
#save_schema
|
215
|
+
# save_schema
|
187
216
|
end
|
217
|
+
# update the weights if they changed
|
218
|
+
@db.execute(@schema.sql_for(:ranks, true)) if changes[:weights]
|
219
|
+
@db.execute_batch(@schema.sql_for(:create_vocab_tables))
|
188
220
|
do_rebuild if requires_rebuild
|
189
|
-
# update the weights if they changed
|
190
|
-
@db.execute(@schema.sql_for(:ranks)) if changes[:weights]
|
191
221
|
end
|
192
222
|
|
193
223
|
def do_rebuild
|
194
224
|
# remove any zero weight columns
|
195
225
|
if @schema.get(:type) == :backed
|
196
226
|
@db.execute_batch(@schema.sql_for(:drop_primary_triggers))
|
197
|
-
if secondary_triggers_sql = @schema.sql_for(:create_secondary_triggers)
|
227
|
+
if (secondary_triggers_sql = @schema.sql_for(:create_secondary_triggers))
|
198
228
|
@db.execute_batch(@schema.sql_for(:drop_secondary_triggers))
|
199
229
|
end
|
200
230
|
@db.execute(@schema.sql_for(:drop))
|
201
231
|
@db.execute(@schema.sql_for(:create_index, true))
|
202
232
|
@db.execute_batch(@schema.sql_for(:create_primary_triggers))
|
203
233
|
@db.execute_batch(secondary_triggers_sql) if secondary_triggers_sql
|
204
|
-
@db.execute(@schema.sql_for(:rebuild))
|
234
|
+
@db.execute(@schema.sql_for(:rebuild))
|
205
235
|
elsif @schema.get(:type) == :standalone
|
206
236
|
removables = []
|
207
|
-
@schema.get(:fields).each_with_index{|f, i| removables << [f[0], i] if f[1][:weight] == 0
|
237
|
+
@schema.get(:fields).each_with_index { |f, i| removables << [f[0], i] if f[1][:weight] == 0 }
|
208
238
|
removables.each do |col|
|
209
239
|
@db.execute(@schema.sql_for(:drop_content_col, col[1]))
|
210
|
-
@schema.get(:fields).delete(col[0])
|
240
|
+
@schema.get(:fields).delete(col[0])
|
211
241
|
end
|
212
242
|
@db.execute("PRAGMA WRITABLE_SCHEMA = TRUE")
|
213
243
|
@db.execute(@schema.sql_for(:update_index), @schema.sql_for(:create_index, true))
|
214
|
-
@db.execute(@schema.sql_for(:update_content_table), @schema.sql_for(:create_content_table, @schema.schema[:fields].count))
|
244
|
+
@db.execute(@schema.sql_for(:update_content_table), @schema.sql_for(:create_content_table, @schema.schema[:fields].count))
|
215
245
|
@db.execute("PRAGMA WRITABLE_SCHEMA = RESET")
|
216
|
-
@db.execute(@schema.sql_for(:rebuild))
|
246
|
+
@db.execute(@schema.sql_for(:rebuild))
|
217
247
|
end
|
248
|
+
@db.execute_batch(@schema.sql_for(:create_vocab_tables))
|
218
249
|
set_config_value(:litesearch_schema, @schema.schema)
|
219
|
-
@db.execute(@schema.sql_for(:ranks, true))
|
220
|
-
|
221
|
-
|
250
|
+
@db.execute(@schema.sql_for(:ranks, true))
|
251
|
+
end
|
252
|
+
|
222
253
|
def get_config_value(key)
|
223
|
-
Oj.load(@db.get_first_value(@schema.sql_for(:get_config_value), key.to_s)) #rescue nil
|
254
|
+
Oj.load(@db.get_first_value(@schema.sql_for(:get_config_value), key.to_s)) # rescue nil
|
224
255
|
end
|
225
|
-
|
256
|
+
|
226
257
|
def set_config_value(key, value)
|
227
258
|
@db.execute(@schema.sql_for(:set_config_value), key.to_s, Oj.dump(value))
|
228
259
|
end
|
229
|
-
|
230
260
|
end
|
@@ -1,61 +1,75 @@
|
|
1
1
|
module Litesearch::Model
|
2
|
-
|
3
2
|
def self.included(klass)
|
4
3
|
klass.include InstanceMethods
|
5
|
-
klass.extend ClassMethods
|
4
|
+
klass.extend ClassMethods
|
6
5
|
klass.attribute :search_rank, :float if klass.respond_to? :attribute
|
7
|
-
if defined?(Sequel::Model)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
elsif defined?(ActiveRecord::Base)
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
if !defined?(Sequel::Model).nil? && klass.ancestors.include?(Sequel::Model)
|
7
|
+
klass.include Litesearch::Model::SequelInstanceMethods
|
8
|
+
klass.extend Litesearch::Model::SequelClassMethods
|
9
|
+
Sequel::Model.extend Litesearch::Model::BaseClassMethods
|
10
|
+
elsif !defined?(ActiveRecord::Base).nil? && klass.ancestors.include?(ActiveRecord::Base)
|
11
|
+
klass.include Litesearch::Model::ActiveRecordInstanceMethods
|
12
|
+
klass.extend Litesearch::Model::ActiveRecordClassMethods
|
13
|
+
ActiveRecord::Base.extend Litesearch::Model::BaseClassMethods
|
15
14
|
end
|
16
15
|
end
|
17
|
-
|
16
|
+
|
18
17
|
module BaseClassMethods
|
19
18
|
def search_models
|
20
19
|
@@models ||= {}
|
21
|
-
end
|
20
|
+
end
|
22
21
|
end
|
23
|
-
|
22
|
+
|
24
23
|
module InstanceMethods
|
25
|
-
|
24
|
+
def similar(limit=10)
|
25
|
+
conn = self.class.get_connection
|
26
|
+
idx = conn.search_index(self.class.send(:index_name))
|
27
|
+
r_a_h = conn.results_as_hash
|
28
|
+
conn.results_as_hash = true
|
29
|
+
rs = idx.similar(id, limit)
|
30
|
+
conn.results_as_hash = r_a_h
|
31
|
+
result = []
|
32
|
+
rs.each do |row|
|
33
|
+
obj = self.class.fetch_row(row["id"])
|
34
|
+
obj.search_rank = row["search_rank"]
|
35
|
+
result << obj
|
36
|
+
end
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
26
40
|
end
|
27
|
-
|
28
|
-
module ClassMethods
|
29
|
-
|
41
|
+
|
42
|
+
module ClassMethods
|
30
43
|
def litesearch
|
31
44
|
idx = get_connection.search_index(index_name) do |schema|
|
32
45
|
schema.type :backed
|
33
46
|
schema.table table_name.to_sym
|
34
47
|
yield schema
|
35
48
|
schema.post_init
|
36
|
-
@schema = schema #save the schema
|
49
|
+
@schema = schema # save the schema
|
37
50
|
end
|
38
|
-
if defined?(Sequel::Model)
|
39
|
-
Sequel::Model.search_models[
|
40
|
-
elsif defined?(ActiveRecord::Base)
|
41
|
-
ActiveRecord::Base.search_models[
|
51
|
+
if !defined?(Sequel::Model).nil? && ancestors.include?(Sequel::Model)
|
52
|
+
Sequel::Model.search_models[name] = self
|
53
|
+
elsif !defined?(ActiveRecord::Base).nil? && ancestors.include?(ActiveRecord::Base)
|
54
|
+
ActiveRecord::Base.search_models[name] = self
|
42
55
|
end
|
43
56
|
idx
|
44
57
|
end
|
45
|
-
|
58
|
+
|
46
59
|
def rebuild_index!
|
47
60
|
get_connection.search_index(index_name).rebuild!
|
48
61
|
end
|
49
|
-
|
62
|
+
|
50
63
|
def drop_index!
|
51
64
|
get_connection.search_index(index_name).drop!
|
52
65
|
end
|
53
|
-
|
54
|
-
def search_all(term, options={})
|
66
|
+
|
67
|
+
def search_all(term, options = {})
|
55
68
|
options[:offset] ||= 0
|
56
69
|
options[:limit] ||= 25
|
57
|
-
|
58
|
-
|
70
|
+
options[:term] = term
|
71
|
+
selects = []
|
72
|
+
if (models = options[:models])
|
59
73
|
models_hash = {}
|
60
74
|
models.each do |model|
|
61
75
|
models_hash[model.name] = model
|
@@ -63,13 +77,15 @@ module Litesearch::Model
|
|
63
77
|
else
|
64
78
|
models_hash = search_models
|
65
79
|
end
|
80
|
+
# remove the models from the options hash before passing it ot the query
|
81
|
+
options.delete(:models)
|
66
82
|
models_hash.each do |name, klass|
|
67
|
-
selects << "SELECT '#{name}' AS model, rowid, -rank AS search_rank FROM #{index_name_for_table(klass.table_name)}(
|
83
|
+
selects << "SELECT '#{name}' AS model, rowid, -rank AS search_rank FROM #{index_name_for_table(klass.table_name)}(:term)"
|
68
84
|
end
|
69
85
|
conn = get_connection
|
70
|
-
sql = selects.join(" UNION ") << " ORDER BY search_rank DESC LIMIT
|
86
|
+
sql = selects.join(" UNION ") << " ORDER BY search_rank DESC LIMIT :limit OFFSET :offset"
|
71
87
|
result = []
|
72
|
-
rs = conn.query(sql)
|
88
|
+
rs = conn.query(sql, options) # , options[:limit], options[:offset])
|
73
89
|
rs.each_hash do |row|
|
74
90
|
obj = models_hash[row["model"]].fetch_row(row["rowid"])
|
75
91
|
obj.search_rank = row["search_rank"]
|
@@ -78,39 +94,32 @@ module Litesearch::Model
|
|
78
94
|
rs.close
|
79
95
|
result
|
80
96
|
end
|
81
|
-
|
82
|
-
# AR specific
|
83
|
-
|
84
|
-
private
|
85
|
-
|
97
|
+
|
86
98
|
def index_name
|
87
99
|
"#{table_name}_search_idx"
|
88
100
|
end
|
89
|
-
|
101
|
+
|
90
102
|
def index_name_for_table(table)
|
91
103
|
"#{table}_search_idx"
|
92
104
|
end
|
93
|
-
|
105
|
+
|
94
106
|
# create a new instance of self with the row as an argument
|
95
107
|
def create_instance(row)
|
96
|
-
|
108
|
+
new(row)
|
97
109
|
end
|
98
|
-
|
99
|
-
|
100
110
|
end
|
101
|
-
|
102
|
-
module ActiveRecordInstanceMethods;end
|
103
|
-
|
111
|
+
|
112
|
+
module ActiveRecordInstanceMethods; end
|
113
|
+
|
104
114
|
module ActiveRecordClassMethods
|
105
|
-
|
106
115
|
def get_connection
|
107
116
|
connection.raw_connection
|
108
117
|
end
|
109
|
-
|
118
|
+
|
110
119
|
def fetch_row(id)
|
111
120
|
find(id)
|
112
121
|
end
|
113
|
-
|
122
|
+
|
114
123
|
def search(term)
|
115
124
|
self.select(
|
116
125
|
"#{table_name}.*"
|
@@ -120,30 +129,25 @@ module Litesearch::Model
|
|
120
129
|
"-#{index_name}.rank AS search_rank"
|
121
130
|
).order(
|
122
131
|
Arel.sql("#{index_name}.rank")
|
123
|
-
)
|
132
|
+
)
|
124
133
|
end
|
125
134
|
|
126
|
-
private
|
127
|
-
|
128
135
|
def create_instance(row)
|
129
136
|
instantiate(row)
|
130
137
|
end
|
131
138
|
end
|
132
|
-
|
139
|
+
|
133
140
|
module SequelInstanceMethods
|
134
|
-
|
135
141
|
def search_rank
|
136
142
|
@values[:search_rank]
|
137
143
|
end
|
138
|
-
|
144
|
+
|
139
145
|
def search_rank=(rank)
|
140
146
|
@values[:search_rank] = rank
|
141
147
|
end
|
142
|
-
|
143
148
|
end
|
144
|
-
|
149
|
+
|
145
150
|
module SequelClassMethods
|
146
|
-
|
147
151
|
def fetch_row(id)
|
148
152
|
self[id]
|
149
153
|
end
|
@@ -156,23 +160,20 @@ module Litesearch::Model
|
|
156
160
|
dataset.select(
|
157
161
|
Sequel.lit("#{table_name}.*, -#{index_name}.rank AS search_rank")
|
158
162
|
).inner_join(
|
159
|
-
Sequel.lit("#{index_name}(
|
163
|
+
Sequel.lit("#{index_name}(:term) ON #{table_name}.id = #{index_name}.rowid AND rank != 0", {term: term})
|
160
164
|
).order(
|
161
|
-
Sequel.lit(
|
165
|
+
Sequel.lit("rank")
|
162
166
|
)
|
163
167
|
end
|
164
168
|
|
165
|
-
private
|
166
|
-
|
167
169
|
def create_instance(row)
|
168
170
|
# we need to convert keys to symbols first!
|
169
171
|
row.keys.each do |k|
|
170
|
-
next if k.is_a? Symbol
|
171
|
-
row[k.to_sym] = row[k]
|
172
|
-
row.delete(k)
|
172
|
+
next if k.is_a? Symbol
|
173
|
+
row[k.to_sym] = row[k]
|
174
|
+
row.delete(k)
|
173
175
|
end
|
174
|
-
|
176
|
+
call(row)
|
175
177
|
end
|
176
178
|
end
|
177
|
-
|
178
179
|
end
|