runestone 1.0 → 2.0.0
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/README.md +101 -1
- data/db/migrate/{20181101150207_create_ts_tables.rb → 20181101150207_create_runestone_tables.rb} +3 -2
- data/lib/runestone.rb +47 -5
- data/lib/runestone/active_record/relation_methods.rb +8 -5
- data/lib/runestone/corpus.rb +4 -3
- data/lib/runestone/version.rb +1 -1
- data/lib/runestone/web_search.rb +1 -5
- data/runestone.gemspec +1 -1
- data/test/corpus_test.rb +20 -1
- data/test/database.rb +2 -2
- data/test/delayed_index_test.rb +2 -2
- data/test/highlight_test.rb +23 -1
- data/test/indexing_test.rb +2 -2
- data/test/multi_index_test.rb +4 -4
- data/test/ordering_test.rb +28 -0
- data/test/query_test.rb +26 -26
- data/test/synonym_test.rb +18 -18
- metadata +11 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c069ec88ae02b52e3cb0a155efe7d17b0cb3d0f9b248e74deec97cb1ed752e0
|
4
|
+
data.tar.gz: 4e627b4879f88ae65b8b56090604e7e8fe0379f93f5a72b4142d76d5eabf08f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f3f103de6f864ce9d8047232023f1c6db98867be4a7015d899c088875b830d9ee34e84c31d23b18bbdb88fc9058efe7a455891958d5adbb6b3600aed0ff4552
|
7
|
+
data.tar.gz: 014ab3c81cb2c6df0473cd5ec0c65a35a6aa46a41c7f351962b26a97abc32eac74820738bcccddfa0d67b5a3b8c715d8ed5a6d1810d1099be1f134d85ac54679
|
data/README.md
CHANGED
@@ -4,7 +4,107 @@ Runestone provides full text search PostgreSQL's full text search capabilities.
|
|
4
4
|
It was inspired by [Postgres full-text search is Good Enough!][1] and
|
5
5
|
[Super Fuzzy Searching on PostgreSQL][2]
|
6
6
|
|
7
|
+
## Installation
|
7
8
|
|
9
|
+
Install Runestone from RubyGems:
|
10
|
+
|
11
|
+
``` sh
|
12
|
+
$ gem install runestone
|
13
|
+
```
|
14
|
+
|
15
|
+
Or include it in your project's `Gemfile` with Bundler:
|
16
|
+
|
17
|
+
``` ruby
|
18
|
+
gem 'runestone'
|
19
|
+
```
|
20
|
+
|
21
|
+
After installation, run the Runestone's migration to to enable the necessary database extensions and create the runestones and runestone corpus tables.
|
22
|
+
|
23
|
+
```sh
|
24
|
+
$ rails db:migrate
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Indexing
|
30
|
+
|
31
|
+
To index your ActiveRecord Models:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class Building < ApplicationRecord
|
35
|
+
|
36
|
+
runestone do
|
37
|
+
index 'name', 'addresses.global', 'addresses.national'
|
38
|
+
|
39
|
+
attributes(:name)
|
40
|
+
attributes(:size, :floors)
|
41
|
+
attribute(:addresses) {
|
42
|
+
addresses&.map{|address| {
|
43
|
+
local: address.local,
|
44
|
+
regional: address.regional,
|
45
|
+
national: address.national,
|
46
|
+
global: address.global
|
47
|
+
} }
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
When searching the attribute(s) will be available in `data` on the result(s), but only the attributes specified by `index` will indexed and used for searching.
|
55
|
+
|
56
|
+
### Searching
|
57
|
+
|
58
|
+
To search for the Building:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
Building.search("Empire")
|
62
|
+
```
|
63
|
+
|
64
|
+
You can also search through all indexed models with:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
Runestone::Model.search("needle")
|
68
|
+
```
|
69
|
+
|
70
|
+
Additionally you can highlight the results. When this is done each result will have a `highlights` attribute which is the same as data, but with matches wrapped in a `<b>` tag:
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
Runestone::Model.highlight(@results, "needle")
|
74
|
+
```
|
75
|
+
|
76
|
+
## Configuration
|
77
|
+
|
78
|
+
### Synonym
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
Runestone.add_synonym('ten', '10')
|
82
|
+
|
83
|
+
Runestone.add_synonym('one hundred', '100')
|
84
|
+
Runestone.add_synonym('100', 'one hundred')
|
85
|
+
```
|
86
|
+
|
87
|
+
### Defaults
|
88
|
+
|
89
|
+
#### dictionary
|
90
|
+
|
91
|
+
The default dictionary that Runestone uses is the `runestone` dictionary. Which
|
92
|
+
is the `simple` dictionary in PostgreSQL with `unaccent` to tranliterate some
|
93
|
+
characters to the ASCII equivlent.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Runestone.dictionary = :runesonte
|
97
|
+
```
|
98
|
+
|
99
|
+
#### normalization for ranking
|
100
|
+
|
101
|
+
Ranking can be configured to use the `normalization` paramater as described
|
102
|
+
in the [PostgreSQL documentation][3]. The default is `16`
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
Runestone.dictionary = 16
|
106
|
+
```
|
8
107
|
|
9
108
|
[1]: http://rachbelaid.com/postgres-full-text-search-is-good-enough/
|
10
|
-
[2]: http://www.www-old.bartlettpublishing.com/site/bartpub/blog/3/entry/350
|
109
|
+
[2]: http://www.www-old.bartlettpublishing.com/site/bartpub/blog/3/entry/350
|
110
|
+
[3]: https://www.postgresql.org/docs/13/textsearch-controls.html#TEXTSEARCH-RANKING
|
data/db/migrate/{20181101150207_create_ts_tables.rb → 20181101150207_create_runestone_tables.rb}
RENAMED
@@ -4,6 +4,7 @@ class CreateRunestoneTables < ActiveRecord::Migration[6.0]
|
|
4
4
|
enable_extension 'pgcrypto'
|
5
5
|
enable_extension 'pg_trgm'
|
6
6
|
enable_extension 'fuzzystrmatch'
|
7
|
+
enable_extension 'unaccent'
|
7
8
|
|
8
9
|
create_table :runestones, id: :uuid do |t|
|
9
10
|
t.belongs_to :record, type: :uuid, polymorphic: true, null: false
|
@@ -21,8 +22,8 @@ class CreateRunestoneTables < ActiveRecord::Migration[6.0]
|
|
21
22
|
|
22
23
|
CREATE INDEX runestone_corpus_trgm_idx ON runestone_corpus USING GIN (word gin_trgm_ops);
|
23
24
|
|
24
|
-
CREATE TEXT SEARCH CONFIGURATION
|
25
|
-
ALTER TEXT SEARCH CONFIGURATION
|
25
|
+
CREATE TEXT SEARCH CONFIGURATION runestone (COPY = simple);
|
26
|
+
ALTER TEXT SEARCH CONFIGURATION runestone
|
26
27
|
ALTER MAPPING FOR hword, hword_part, word
|
27
28
|
WITH unaccent, simple;
|
28
29
|
SQL
|
data/lib/runestone.rb
CHANGED
@@ -6,7 +6,8 @@ module Runestone
|
|
6
6
|
autoload :WebSearch, "#{File.dirname(__FILE__)}/runestone/web_search"
|
7
7
|
autoload :IndexingJob, "#{File.dirname(__FILE__)}/runestone/indexing_job"
|
8
8
|
|
9
|
-
mattr_accessor :dictionary, default: :
|
9
|
+
mattr_accessor :dictionary, default: :runestone
|
10
|
+
mattr_accessor :normalization, default: 16
|
10
11
|
mattr_accessor :runner, default: :inline
|
11
12
|
mattr_accessor :job_queue, default: :runestone_indexing
|
12
13
|
mattr_accessor :typo_tolerances, default: { 1 => 4..7, 2 => 8.. }
|
@@ -15,6 +16,37 @@ module Runestone
|
|
15
16
|
{ }
|
16
17
|
end
|
17
18
|
|
19
|
+
DEFAULT_APPROXIMATIONS = {
|
20
|
+
"À"=>"A", "Á"=>"A", "Â"=>"A", "Ã"=>"A", "Ä"=>"A", "Å"=>"A", "Æ"=>"AE",
|
21
|
+
"Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I",
|
22
|
+
"Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O",
|
23
|
+
"Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U",
|
24
|
+
"Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a",
|
25
|
+
"ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e",
|
26
|
+
"ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d",
|
27
|
+
"ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o",
|
28
|
+
"ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y",
|
29
|
+
"Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C",
|
30
|
+
"ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c",
|
31
|
+
"Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E",
|
32
|
+
"ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e",
|
33
|
+
"Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G",
|
34
|
+
"ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i",
|
35
|
+
"Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I",
|
36
|
+
"ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k",
|
37
|
+
"ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l",
|
38
|
+
"Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N",
|
39
|
+
"ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng",
|
40
|
+
"Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE",
|
41
|
+
"œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r",
|
42
|
+
"Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S",
|
43
|
+
"š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t",
|
44
|
+
"Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U",
|
45
|
+
"ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w",
|
46
|
+
"Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z",
|
47
|
+
"Ž"=>"Z", "ž"=>"z"
|
48
|
+
}.freeze
|
49
|
+
|
18
50
|
def self.normalize(string)
|
19
51
|
string = string.downcase
|
20
52
|
string = string.unicode_normalize!
|
@@ -22,7 +54,17 @@ module Runestone
|
|
22
54
|
rescue Encoding::CompatibilityError
|
23
55
|
string
|
24
56
|
end
|
25
|
-
|
57
|
+
|
58
|
+
def self.normalize!(string)
|
59
|
+
string.downcase!
|
60
|
+
string.unicode_normalize!
|
61
|
+
rescue Encoding::CompatibilityError
|
62
|
+
end
|
63
|
+
|
64
|
+
def transliterate(string)
|
65
|
+
string.gsub(/[^\x00-\x7f]/u) { |char| approximations[char] || char }
|
66
|
+
end
|
67
|
+
|
26
68
|
def self.add_synonyms(dictionary)
|
27
69
|
dictionary.each do |k, v|
|
28
70
|
add_synonym(k, *v)
|
@@ -53,7 +95,7 @@ module Runestone
|
|
53
95
|
syn[last].uniq!
|
54
96
|
end
|
55
97
|
|
56
|
-
def search(query, dictionary: nil, prefix: :last)
|
98
|
+
def search(query, dictionary: nil, prefix: :last, normalization: nil)
|
57
99
|
exact_search = Runestone::WebSearch.parse(query, prefix: prefix)
|
58
100
|
typo_search = exact_search.typos
|
59
101
|
syn_search = typo_search.synonymize
|
@@ -65,11 +107,11 @@ module Runestone
|
|
65
107
|
q = if select_values.empty?
|
66
108
|
select(
|
67
109
|
klass.arel_table[Arel.star],
|
68
|
-
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
110
|
+
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary, normalization: normalization), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
69
111
|
)
|
70
112
|
else
|
71
113
|
select(
|
72
|
-
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
114
|
+
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary, normalization: normalization), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
73
115
|
)
|
74
116
|
end
|
75
117
|
|
@@ -39,14 +39,17 @@ module Runestone::ActiveRecord
|
|
39
39
|
)
|
40
40
|
end
|
41
41
|
|
42
|
-
def ts_rank_cd(vector, query, dictionary: nil)
|
42
|
+
def ts_rank_cd(vector, query, dictionary: nil, normalization: nil)
|
43
|
+
normalization ||= Runestone.normalization
|
44
|
+
|
43
45
|
Arel::Nodes::TSRankCD.new(
|
44
46
|
ts_vector(vector, dictionary: dictionary),
|
45
|
-
ts_query(query, dictionary: dictionary)
|
47
|
+
ts_query(query, dictionary: dictionary),
|
48
|
+
normalization
|
46
49
|
)
|
47
50
|
end
|
48
51
|
|
49
|
-
def search(query, dictionary: nil, prefix: nil)
|
52
|
+
def search(query, dictionary: nil, prefix: nil, normalization: nil)
|
50
53
|
exact_search = Runestone::WebSearch.parse(query, prefix: prefix)
|
51
54
|
typo_search = exact_search.typos
|
52
55
|
syn_search = typo_search.synonymize
|
@@ -58,11 +61,11 @@ module Runestone::ActiveRecord
|
|
58
61
|
q = if select_values.empty?
|
59
62
|
select(
|
60
63
|
klass.arel_table[Arel.star],
|
61
|
-
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
64
|
+
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary, normalization: normalization), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
62
65
|
)
|
63
66
|
else
|
64
67
|
select(
|
65
|
-
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
68
|
+
*tsqueries.each_with_index.map { |q, i| Arel::Nodes::As.new(ts_rank_cd(:vector, q, dictionary: dictionary, normalization: normalization), Arel::Nodes::SqlLiteral.new("rank#{i}")) }
|
66
69
|
)
|
67
70
|
end
|
68
71
|
|
data/lib/runestone/corpus.rb
CHANGED
@@ -6,21 +6,22 @@ module Runestone::Corpus
|
|
6
6
|
conn = Runestone::Model.connection
|
7
7
|
conn.execute(<<-SQL)
|
8
8
|
INSERT INTO runestone_corpus ( word )
|
9
|
-
VALUES (#{words.map { |w| conn.quote(w
|
9
|
+
VALUES (#{words.map { |w| conn.quote(Runestone.normalize(w)) }.join('),(')})
|
10
10
|
ON CONFLICT DO NOTHING
|
11
11
|
SQL
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.similar_words(*words)
|
15
15
|
lut = {}
|
16
|
+
conn = Runestone::Model.connection
|
16
17
|
words = words.inject([]) do |ws, w|
|
17
18
|
tt = typo_tolerance(w)
|
18
|
-
ws << "#{
|
19
|
+
ws << "#{conn.quote(w)}, #{conn.quote(w.downcase)}, #{tt}" if tt > 0
|
19
20
|
ws
|
20
21
|
end
|
21
22
|
return lut if words.size == 0
|
22
23
|
|
23
|
-
result =
|
24
|
+
result = conn.execute(<<-SQL)
|
24
25
|
WITH tokens (token, token_downcased, typo_tolerance) AS (VALUES (#{words.join('), (')}))
|
25
26
|
SELECT token, word, levenshtein(runestone_corpus.word, tokens.token_downcased)
|
26
27
|
FROM tokens
|
data/lib/runestone/version.rb
CHANGED
data/lib/runestone/web_search.rb
CHANGED
@@ -26,11 +26,7 @@ class Runestone::WebSearch
|
|
26
26
|
# prefix options: :all, :last, :none (default: :last)
|
27
27
|
def self.parse(query, prefix: :last)
|
28
28
|
prefix ||= :last
|
29
|
-
|
30
|
-
query.unicode_normalize!
|
31
|
-
rescue Encoding::CompatibilityError
|
32
|
-
end
|
33
|
-
query.downcase!
|
29
|
+
Runestone.normalize!(query)
|
34
30
|
|
35
31
|
q = []
|
36
32
|
stack = []
|
data/runestone.gemspec
CHANGED
@@ -27,6 +27,6 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.add_development_dependency 'activejob', '>= 6.0'
|
28
28
|
|
29
29
|
# Runtime
|
30
|
-
s.add_runtime_dependency 'arel-extensions', '>= 6.0'
|
30
|
+
s.add_runtime_dependency 'arel-extensions', '>= 6.0.0.9'
|
31
31
|
s.add_runtime_dependency 'activerecord', '>= 6.0'
|
32
32
|
end
|
data/test/corpus_test.rb
CHANGED
@@ -38,5 +38,24 @@ class CorpusTest < ActiveSupport::TestCase
|
|
38
38
|
Runestone::Corpus.similar_words('Allee')
|
39
39
|
)
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
|
+
test 'adding words to corpus normalizes them' do
|
43
|
+
Runestone::Corpus.add("all\u00e9e")
|
44
|
+
assert_equal(
|
45
|
+
{
|
46
|
+
"Allee" => ["all\u00e9e"]
|
47
|
+
},
|
48
|
+
Runestone::Corpus.similar_words('Allee')
|
49
|
+
)
|
50
|
+
|
51
|
+
Runestone::Model.connection.execute('DELETE FROM runestone_corpus')
|
52
|
+
Runestone::Corpus.add("all\u0065\u0301e")
|
53
|
+
assert_equal(
|
54
|
+
{
|
55
|
+
"Allee" => ["all\u00e9e"]
|
56
|
+
},
|
57
|
+
Runestone::Corpus.similar_words('Allee')
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
42
61
|
end
|
data/test/database.rb
CHANGED
@@ -56,8 +56,8 @@ ActiveRecord::Migration.suppress_messages do
|
|
56
56
|
CREATE INDEX runestone_corpus_trgm_idx ON runestone_corpus USING GIN (word gin_trgm_ops);
|
57
57
|
|
58
58
|
|
59
|
-
CREATE TEXT SEARCH CONFIGURATION
|
60
|
-
ALTER TEXT SEARCH CONFIGURATION
|
59
|
+
CREATE TEXT SEARCH CONFIGURATION runestone (COPY = simple);
|
60
|
+
ALTER TEXT SEARCH CONFIGURATION runestone
|
61
61
|
ALTER MAPPING FOR hword, hword_part, word
|
62
62
|
WITH unaccent, simple;
|
63
63
|
SQL
|
data/test/delayed_index_test.rb
CHANGED
@@ -2,9 +2,9 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class DelayedIndexingTest < ActiveSupport::TestCase
|
4
4
|
|
5
|
-
test '
|
5
|
+
test 'runestone index' do
|
6
6
|
region = assert_no_difference 'Runestone::Model.count' do
|
7
|
-
assert_no_sql(/setweight\(to_tsvector\('
|
7
|
+
assert_no_sql(/setweight\(to_tsvector\('runestone', 'address name'\), 'A'\)/) do
|
8
8
|
Region.create(name: 'Region name')
|
9
9
|
end
|
10
10
|
end
|
data/test/highlight_test.rb
CHANGED
@@ -9,6 +9,7 @@ class HighlightTest < ActiveSupport::TestCase
|
|
9
9
|
tsmodels = Runestone::Model.search('state')
|
10
10
|
Runestone::Model.highlight(tsmodels, 'state')
|
11
11
|
assert_equal([
|
12
|
+
{ "name"=>"address of <b>state</b> duo" },
|
12
13
|
{
|
13
14
|
"name"=>"Big <b>state</b> building",
|
14
15
|
"addresses"=> [{"name"=>"address of <b>state</b> duo"}]
|
@@ -17,10 +18,31 @@ class HighlightTest < ActiveSupport::TestCase
|
|
17
18
|
"name"=>"Empire <b>state</b> building",
|
18
19
|
"addresses"=> [{"name"=>"address uno"}]
|
19
20
|
},
|
21
|
+
|
22
|
+
], tsmodels.map(&:highlights))
|
23
|
+
end
|
24
|
+
|
25
|
+
test '::highlights(query) with an accent in the result' do
|
26
|
+
Property.create(name: 'Émpire state building', addresses: [Address.create(name: 'address uno')])
|
27
|
+
Property.create(name: 'Big state building', addresses: [Address.create(name: 'addréss of state duo')])
|
28
|
+
|
29
|
+
tsmodels = Runestone::Model.search('empire')
|
30
|
+
Runestone::Model.highlight(tsmodels, 'empire')
|
31
|
+
assert_equal([
|
20
32
|
{
|
21
|
-
"name"=>"
|
33
|
+
"name"=>"<b>Émpire</b> state building",
|
34
|
+
"addresses"=>[ {"name"=>"address uno"} ]
|
22
35
|
}
|
23
36
|
], tsmodels.map(&:highlights))
|
37
|
+
|
38
|
+
tsmodels = Runestone::Model.search('address')
|
39
|
+
Runestone::Model.highlight(tsmodels, 'address')
|
40
|
+
assert_equal([
|
41
|
+
{"name"=>"<b>address</b> uno"},
|
42
|
+
{"name"=>"<b>addréss</b> of state duo"},
|
43
|
+
{"addresses"=>[{"name"=>"<b>address</b> uno"}], "name"=>"Émpire state building"},
|
44
|
+
{"addresses"=>[{"name"=>"<b>addréss</b> of state duo"}], "name"=>"Big state building"}
|
45
|
+
], tsmodels.map(&:highlights))
|
24
46
|
end
|
25
47
|
|
26
48
|
end
|
data/test/indexing_test.rb
CHANGED
@@ -2,9 +2,9 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class IndexingTest < ActiveSupport::TestCase
|
4
4
|
|
5
|
-
test '
|
5
|
+
test 'runestone index' do
|
6
6
|
address = assert_difference 'Runestone::Model.count', 1 do
|
7
|
-
assert_sql(/setweight\(to_tsvector\('
|
7
|
+
assert_sql(/setweight\(to_tsvector\('runestone', 'address name'\), 'A'\)/) do
|
8
8
|
Address.create(name: 'Address name')
|
9
9
|
end
|
10
10
|
end
|
data/test/multi_index_test.rb
CHANGED
@@ -33,16 +33,16 @@ class MultiIndexTest < ActiveSupport::TestCase
|
|
33
33
|
|
34
34
|
query = Runestone::Model.search('empire')
|
35
35
|
assert_sql(<<~SQL, query.to_sql)
|
36
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
36
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'empire:*'), 16) AS rank0
|
37
37
|
FROM "runestones"
|
38
|
-
WHERE "runestones"."vector" @@ to_tsquery('
|
38
|
+
WHERE "runestones"."vector" @@ to_tsquery('runestone', 'empire:*')
|
39
39
|
ORDER BY rank0 DESC
|
40
40
|
SQL
|
41
41
|
|
42
42
|
query = Runestone::Model.search('empire', dictionary: 'english')
|
43
43
|
assert_sql(<<~SQL, query.to_sql)
|
44
44
|
SELECT
|
45
|
-
"runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('english', 'empire:*')) AS rank0
|
45
|
+
"runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('english', 'empire:*'), 16) AS rank0
|
46
46
|
FROM "runestones"
|
47
47
|
WHERE "runestones"."vector" @@ to_tsquery('english', 'empire:*')
|
48
48
|
AND "runestones"."dictionary" = 'english'
|
@@ -51,7 +51,7 @@ class MultiIndexTest < ActiveSupport::TestCase
|
|
51
51
|
|
52
52
|
query = Runestone::Model.search('Эмпайр', dictionary: 'russian')
|
53
53
|
assert_sql(<<~SQL, query.to_sql)
|
54
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('russian', 'эмпайр:*')) AS rank0
|
54
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('russian', 'эмпайр:*'), 16) AS rank0
|
55
55
|
FROM "runestones"
|
56
56
|
WHERE "runestones"."vector" @@ to_tsquery('russian', 'эмпайр:*')
|
57
57
|
AND "runestones"."dictionary" = 'russian'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class OrderTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
test 'smaller documents come first' do
|
6
|
+
a2 = Address.create(name: 'a big square')
|
7
|
+
a1 = Address.create(name: 'Square')
|
8
|
+
|
9
|
+
query = Runestone::Model.search('square')
|
10
|
+
assert_sql(<<~SQL, query.to_sql)
|
11
|
+
SELECT
|
12
|
+
"runestones".*,
|
13
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'square:*'), 16) AS rank0
|
14
|
+
FROM "runestones"
|
15
|
+
WHERE
|
16
|
+
"runestones"."vector" @@ to_tsquery('runestone', 'square:*')
|
17
|
+
ORDER BY rank0 DESC
|
18
|
+
SQL
|
19
|
+
|
20
|
+
assert_equal(query.map(&:record).map(&:name), [
|
21
|
+
'Square',
|
22
|
+
'a big square'
|
23
|
+
])
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
end
|
data/test/query_test.rb
CHANGED
@@ -6,9 +6,9 @@ class QueryTest < ActiveSupport::TestCase
|
|
6
6
|
query = Runestone::Model.search('seaerch for this')
|
7
7
|
|
8
8
|
assert_sql(<<~SQL, query.to_sql)
|
9
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
9
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'seaerch & for & this:*'), 16) AS rank0
|
10
10
|
FROM "runestones"
|
11
|
-
WHERE "runestones"."vector" @@ to_tsquery('
|
11
|
+
WHERE "runestones"."vector" @@ to_tsquery('runestone', 'seaerch & for & this:*')
|
12
12
|
ORDER BY rank0 DESC
|
13
13
|
SQL
|
14
14
|
end
|
@@ -17,9 +17,9 @@ class QueryTest < ActiveSupport::TestCase
|
|
17
17
|
query = Runestone::Model.search("the search for \u0065\u0301")
|
18
18
|
|
19
19
|
assert_sql(<<~SQL, query.to_sql)
|
20
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
20
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'the & search & for & \u00e9:*'), 16) AS rank0
|
21
21
|
FROM "runestones"
|
22
|
-
WHERE "runestones"."vector" @@ to_tsquery('
|
22
|
+
WHERE "runestones"."vector" @@ to_tsquery('runestone', 'the & search & for & \u00e9:*')
|
23
23
|
ORDER BY rank0 DESC
|
24
24
|
SQL
|
25
25
|
end
|
@@ -27,17 +27,17 @@ class QueryTest < ActiveSupport::TestCase
|
|
27
27
|
test "::search(query with ')" do
|
28
28
|
query = Runestone::Model.search("seaerch for ' this")
|
29
29
|
assert_sql(<<~SQL, query.to_sql)
|
30
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
30
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'seaerch & for & this:*'), 16) AS rank0
|
31
31
|
FROM "runestones"
|
32
|
-
WHERE "runestones"."vector" @@ to_tsquery('
|
32
|
+
WHERE "runestones"."vector" @@ to_tsquery('runestone', 'seaerch & for & this:*')
|
33
33
|
ORDER BY rank0 DESC
|
34
34
|
SQL
|
35
35
|
|
36
36
|
query = Runestone::Model.search("seaerch for james' map")
|
37
37
|
assert_sql(<<~SQL, query.to_sql)
|
38
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
38
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'seaerch & for & james'' & map:*'), 16) AS rank0
|
39
39
|
FROM "runestones"
|
40
|
-
WHERE "runestones"."vector" @@ to_tsquery('
|
40
|
+
WHERE "runestones"."vector" @@ to_tsquery('runestone', 'seaerch & for & james'' & map:*')
|
41
41
|
ORDER BY rank0 DESC
|
42
42
|
SQL
|
43
43
|
end
|
@@ -46,9 +46,9 @@ class QueryTest < ActiveSupport::TestCase
|
|
46
46
|
query = Runestone::Model.search('seaerch for this', prefix: :all)
|
47
47
|
|
48
48
|
assert_sql(<<~SQL, query.to_sql)
|
49
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
49
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'seaerch:* & for:* & this:*'), 16) AS rank0
|
50
50
|
FROM "runestones"
|
51
|
-
WHERE "runestones"."vector" @@ to_tsquery('
|
51
|
+
WHERE "runestones"."vector" @@ to_tsquery('runestone', 'seaerch:* & for:* & this:*')
|
52
52
|
ORDER BY rank0 DESC
|
53
53
|
SQL
|
54
54
|
end
|
@@ -57,9 +57,9 @@ class QueryTest < ActiveSupport::TestCase
|
|
57
57
|
query = Runestone::Model.search('seaerch for this').limit(10)
|
58
58
|
|
59
59
|
assert_sql(<<~SQL, query.to_sql)
|
60
|
-
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
60
|
+
SELECT "runestones".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'seaerch & for & this:*'), 16) AS rank0
|
61
61
|
FROM "runestones"
|
62
|
-
WHERE "runestones"."vector" @@ to_tsquery('
|
62
|
+
WHERE "runestones"."vector" @@ to_tsquery('runestone', 'seaerch & for & this:*')
|
63
63
|
ORDER BY rank0 DESC
|
64
64
|
LIMIT 10
|
65
65
|
SQL
|
@@ -70,13 +70,13 @@ class QueryTest < ActiveSupport::TestCase
|
|
70
70
|
|
71
71
|
assert_sql(<<~SQL, query.to_sql)
|
72
72
|
SELECT
|
73
|
-
"properties".*, ts_rank_cd("runestones"."vector", to_tsquery('
|
73
|
+
"properties".*, ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'seaerch & for & this:*'), 16) AS rank0
|
74
74
|
FROM "properties"
|
75
75
|
INNER JOIN "runestones"
|
76
|
-
ON "runestones"."
|
77
|
-
AND "runestones"."
|
76
|
+
ON "runestones"."record_type" = 'Property'
|
77
|
+
AND "runestones"."record_id" = "properties"."id"
|
78
78
|
WHERE
|
79
|
-
"runestones"."vector" @@ to_tsquery('
|
79
|
+
"runestones"."vector" @@ to_tsquery('runestone', 'seaerch & for & this:*')
|
80
80
|
ORDER BY rank0 DESC
|
81
81
|
SQL
|
82
82
|
end
|
@@ -88,14 +88,14 @@ class QueryTest < ActiveSupport::TestCase
|
|
88
88
|
assert_sql(<<~SQL, query.to_sql)
|
89
89
|
SELECT
|
90
90
|
"properties".*,
|
91
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
92
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
91
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'seaerch & for & this:*'), 16) AS rank0,
|
92
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '(seaerch | search) & for & this:*'), 16) AS rank1
|
93
93
|
FROM "properties"
|
94
|
-
INNER JOIN "runestones"
|
95
|
-
"runestones"."
|
96
|
-
AND "runestones"."
|
94
|
+
INNER JOIN "runestones"
|
95
|
+
ON "runestones"."record_type" = 'Property'
|
96
|
+
AND "runestones"."record_id" = "properties"."id"
|
97
97
|
WHERE
|
98
|
-
"runestones"."vector" @@ to_tsquery('
|
98
|
+
"runestones"."vector" @@ to_tsquery('runestone', '(seaerch | search) & for & this:*')
|
99
99
|
ORDER BY
|
100
100
|
rank0 DESC,
|
101
101
|
rank1 DESC
|
@@ -113,12 +113,12 @@ class QueryTest < ActiveSupport::TestCase
|
|
113
113
|
assert_sql(<<~SQL, Runestone::Model.search('avenue').to_sql)
|
114
114
|
SELECT
|
115
115
|
"runestones".*,
|
116
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
117
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
118
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
116
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'avenue:*'), 16) AS rank0,
|
117
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '(avenue:* | aveneue)'), 16) AS rank1,
|
118
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '((avenue:* | aveneue) | av | ave | avn | aven | avenu | avnue)'), 16) AS rank2
|
119
119
|
FROM "runestones"
|
120
120
|
WHERE
|
121
|
-
"runestones"."vector" @@ to_tsquery('
|
121
|
+
"runestones"."vector" @@ to_tsquery('runestone', '((avenue:* | aveneue) | av | ave | avn | aven | avenu | avnue)')
|
122
122
|
ORDER BY
|
123
123
|
rank0 DESC,
|
124
124
|
rank1 DESC,
|
data/test/synonym_test.rb
CHANGED
@@ -13,11 +13,11 @@ class SynonymTest < ActiveSupport::TestCase
|
|
13
13
|
assert_sql(<<~SQL, query.to_sql)
|
14
14
|
SELECT
|
15
15
|
"runestones".*,
|
16
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
17
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
16
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '17 & spruce:*'), 16) AS rank0,
|
17
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & (spruce:* | pine)'), 16) AS rank1
|
18
18
|
FROM "runestones"
|
19
19
|
WHERE
|
20
|
-
"runestones"."vector" @@ to_tsquery('
|
20
|
+
"runestones"."vector" @@ to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & (spruce:* | pine)')
|
21
21
|
ORDER BY rank0 DESC, rank1 DESC
|
22
22
|
SQL
|
23
23
|
end
|
@@ -40,11 +40,11 @@ class SynonymTest < ActiveSupport::TestCase
|
|
40
40
|
assert_sql(<<~SQL, query.to_sql)
|
41
41
|
SELECT
|
42
42
|
"runestones".*,
|
43
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
44
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
43
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '17 & spruce:*'), 16) AS rank0,
|
44
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & (spruce:* | pine)'), 16) AS rank1
|
45
45
|
FROM "runestones"
|
46
46
|
WHERE
|
47
|
-
"runestones"."vector" @@ to_tsquery('
|
47
|
+
"runestones"."vector" @@ to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & (spruce:* | pine)')
|
48
48
|
ORDER BY rank0 DESC, rank1 DESC
|
49
49
|
SQL
|
50
50
|
end
|
@@ -59,11 +59,11 @@ class SynonymTest < ActiveSupport::TestCase
|
|
59
59
|
assert_sql(<<~SQL, query.to_sql)
|
60
60
|
SELECT
|
61
61
|
"runestones".*,
|
62
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
63
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
62
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '17 & !spruce'), 16) AS rank0,
|
63
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & !spruce'), 16) AS rank1
|
64
64
|
FROM "runestones"
|
65
65
|
WHERE
|
66
|
-
"runestones"."vector" @@ to_tsquery('
|
66
|
+
"runestones"."vector" @@ to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & !spruce')
|
67
67
|
ORDER BY rank0 DESC, rank1 DESC
|
68
68
|
SQL
|
69
69
|
end
|
@@ -78,11 +78,11 @@ class SynonymTest < ActiveSupport::TestCase
|
|
78
78
|
assert_sql(<<~SQL, query.to_sql)
|
79
79
|
SELECT
|
80
80
|
"runestones".*,
|
81
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
82
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
81
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '17 & spruce'), 16) AS rank0,
|
82
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & spruce'), 16) AS rank1
|
83
83
|
FROM "runestones"
|
84
84
|
WHERE
|
85
|
-
"runestones"."vector" @@ to_tsquery('
|
85
|
+
"runestones"."vector" @@ to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & spruce')
|
86
86
|
ORDER BY rank0 DESC, rank1 DESC
|
87
87
|
SQL
|
88
88
|
end
|
@@ -98,11 +98,11 @@ class SynonymTest < ActiveSupport::TestCase
|
|
98
98
|
assert_sql(<<~SQL, query.to_sql)
|
99
99
|
SELECT
|
100
100
|
"runestones".*,
|
101
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
102
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
101
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '17 & spruce:*'), 16) AS rank0,
|
102
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & (spruce:* | pine)'), 16) AS rank1
|
103
103
|
FROM "runestones"
|
104
104
|
WHERE
|
105
|
-
"runestones"."vector" @@ to_tsquery('
|
105
|
+
"runestones"."vector" @@ to_tsquery('runestone', '(17 | 17th | seventeen | seventeenth) & (spruce:* | pine)')
|
106
106
|
ORDER BY rank0 DESC, rank1 DESC
|
107
107
|
SQL
|
108
108
|
end
|
@@ -116,11 +116,11 @@ class SynonymTest < ActiveSupport::TestCase
|
|
116
116
|
assert_sql(<<~SQL, query.to_sql)
|
117
117
|
SELECT
|
118
118
|
"runestones".*,
|
119
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
120
|
-
ts_rank_cd("runestones"."vector", to_tsquery('
|
119
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', 'one & hundred & spruce:*'), 16) AS rank0,
|
120
|
+
ts_rank_cd("runestones"."vector", to_tsquery('runestone', '((one & hundred | 100) & spruce:* | (one & hundred | one hundy) & spruce:*)'), 16) AS rank1
|
121
121
|
FROM "runestones"
|
122
122
|
WHERE
|
123
|
-
"runestones"."vector" @@ to_tsquery('
|
123
|
+
"runestones"."vector" @@ to_tsquery('runestone', '((one & hundred | 100) & spruce:* | (one & hundred | one hundy) & spruce:*)')
|
124
124
|
ORDER BY rank0 DESC, rank1 DESC
|
125
125
|
SQL
|
126
126
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: runestone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Bracy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - ">="
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
145
|
+
version: 6.0.0.9
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version:
|
152
|
+
version: 6.0.0.9
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: activerecord
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,7 +177,7 @@ files:
|
|
177
177
|
- LICENSE
|
178
178
|
- README.md
|
179
179
|
- Rakefile
|
180
|
-
- db/migrate/
|
180
|
+
- db/migrate/20181101150207_create_runestone_tables.rb
|
181
181
|
- lib/runestone.rb
|
182
182
|
- lib/runestone/active_record/base_methods.rb
|
183
183
|
- lib/runestone/active_record/relation_methods.rb
|
@@ -200,6 +200,7 @@ files:
|
|
200
200
|
- test/highlight_test.rb
|
201
201
|
- test/indexing_test.rb
|
202
202
|
- test/multi_index_test.rb
|
203
|
+
- test/ordering_test.rb
|
203
204
|
- test/query_test.rb
|
204
205
|
- test/synonym_test.rb
|
205
206
|
- test/test_helper.rb
|
@@ -207,7 +208,7 @@ homepage: https://github.com/malomalo/runestone
|
|
207
208
|
licenses:
|
208
209
|
- MIT
|
209
210
|
metadata: {}
|
210
|
-
post_install_message:
|
211
|
+
post_install_message:
|
211
212
|
rdoc_options: []
|
212
213
|
require_paths:
|
213
214
|
- lib
|
@@ -222,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
222
223
|
- !ruby/object:Gem::Version
|
223
224
|
version: '0'
|
224
225
|
requirements: []
|
225
|
-
rubygems_version: 3.
|
226
|
-
signing_key:
|
226
|
+
rubygems_version: 3.1.4
|
227
|
+
signing_key:
|
227
228
|
specification_version: 4
|
228
229
|
summary: Full Text Search for Active Record / Rails
|
229
230
|
test_files:
|
@@ -234,6 +235,7 @@ test_files:
|
|
234
235
|
- test/highlight_test.rb
|
235
236
|
- test/indexing_test.rb
|
236
237
|
- test/multi_index_test.rb
|
238
|
+
- test/ordering_test.rb
|
237
239
|
- test/query_test.rb
|
238
240
|
- test/synonym_test.rb
|
239
241
|
- test/test_helper.rb
|