litestack 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.standard.yml +3 -0
- data/BENCHMARKS.md +23 -7
- data/CHANGELOG.md +11 -0
- data/Gemfile +1 -7
- data/Gemfile.lock +92 -0
- data/README.md +120 -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 +10 -13
- data/bench/bench_cache_raw.rb +17 -22
- 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/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 +65 -75
- data/lib/active_support/cache/litecache.rb +38 -41
- data/lib/generators/litestack/install/install_generator.rb +3 -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 +79 -88
- data/lib/litestack/litecache.sql.yml +81 -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 +15 -15
- 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 +76 -86
- 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 +11 -15
- 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 +101 -6
@@ -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
|