typesensual 0.5.0 → 1.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/Gemfile.lock +7 -5
- data/README.md +2 -7
- data/lib/tasks/typesensual.rake +8 -0
- data/lib/typesensual/collection.rb +1 -0
- data/lib/typesensual/index.rb +0 -2
- data/lib/typesensual/rake_helper.rb +34 -1
- data/lib/typesensual/search/facet.rb +27 -0
- data/lib/typesensual/search/results.rb +13 -2
- data/lib/typesensual/search.rb +137 -9
- data/lib/typesensual/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9fa2afbbada09440e9505cc8f26a67214ae8400489174d396afc9d10b2c2c5a
|
4
|
+
data.tar.gz: 92efdf121fd63031670750d0b3fc200343df494d6a7192f298d267d635aef2a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9994f3f96fb7b84fe5360cb676f9c4cc049f1e3265d7be1f336cb2a673872672a899d71ff6f3402efffbbc277baf03923c70041b0e290f853b05fbe7f504e03
|
7
|
+
data.tar.gz: a67ae00d0e893f3fa57f70838b893959c25447efaf33e7d735b2d818407beec71b96e3aacb1cc62f8846a0bfa342a89706827d3a08e87fa2a102e2118ef8f6f7
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
typesensual (0.
|
4
|
+
typesensual (1.0.0)
|
5
5
|
activesupport (>= 6.1.5)
|
6
6
|
paint (>= 2.0.0)
|
7
7
|
typesense (>= 0.13.0)
|
@@ -15,18 +15,20 @@ GEM
|
|
15
15
|
minitest (>= 5.1)
|
16
16
|
tzinfo (~> 2.0)
|
17
17
|
ast (2.4.2)
|
18
|
+
bigdecimal (3.1.7)
|
18
19
|
commonmarker (0.23.10)
|
19
|
-
concurrent-ruby (1.2.
|
20
|
+
concurrent-ruby (1.2.3)
|
20
21
|
diff-lcs (1.5.0)
|
21
22
|
docile (1.4.0)
|
22
23
|
ethon (0.16.0)
|
23
24
|
ffi (>= 1.15.0)
|
24
|
-
ffi (1.
|
25
|
+
ffi (1.16.3)
|
25
26
|
i18n (1.14.1)
|
26
27
|
concurrent-ruby (~> 1.0)
|
27
28
|
json (2.6.3)
|
28
|
-
minitest (5.
|
29
|
-
oj (3.16.
|
29
|
+
minitest (5.22.3)
|
30
|
+
oj (3.16.3)
|
31
|
+
bigdecimal (>= 3.0)
|
30
32
|
paint (2.3.0)
|
31
33
|
parallel (1.23.0)
|
32
34
|
parser (3.2.2.1)
|
data/README.md
CHANGED
@@ -117,13 +117,8 @@ Once you have defined your index, you can load data into it and update the alias
|
|
117
117
|
indexed data. Typesensual provides rake tasks for this purpose if you use ActiveRecord:
|
118
118
|
|
119
119
|
```console
|
120
|
-
$ bundle exec rake typesensual:
|
121
|
-
==>
|
122
|
-
|
123
|
-
$ bundle exec rake typesensual:update_alias[MoviesIndex,1690076097]
|
124
|
-
==> Alias for MoviesIndex
|
125
|
-
Old: None (N/A)
|
126
|
-
New: 1690076097 (2023-05-07 18:01:37)
|
120
|
+
$ bundle exec rake typesensual:reindex[MoviesIndex,Movie]
|
121
|
+
==> Reindexing Movie into MoviesIndex (Version 1690076097)
|
127
122
|
```
|
128
123
|
|
129
124
|
Otherwise you can do similar to the following:
|
data/lib/tasks/typesensual.rake
CHANGED
@@ -24,6 +24,14 @@ namespace :typesensual do
|
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
27
|
+
desc 'Index all records from a model into a new version then update the alias of the index'
|
28
|
+
task :reindex, %i[index model] => :environment do |_, args|
|
29
|
+
Typesensual::RakeHelper.reindex(
|
30
|
+
index: args[:index],
|
31
|
+
model: args[:model]
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
27
35
|
desc 'Delete a version of an index'
|
28
36
|
task :drop_version, %i[index version] => :environment do |_, args|
|
29
37
|
Typesensual::RakeHelper.drop_version(
|
@@ -32,6 +32,7 @@ class Typesensual
|
|
32
32
|
# * `num_documents` [Integer] the number of documents in the collection
|
33
33
|
# * `symbols_to_index` [String] the symbols to index
|
34
34
|
# * `token_separators` [String] the token separators
|
35
|
+
#
|
35
36
|
# @overload initialize(name)
|
36
37
|
# Initialize a new collection, loading info from Typesense
|
37
38
|
#
|
data/lib/typesensual/index.rb
CHANGED
@@ -96,8 +96,6 @@ class Typesensual
|
|
96
96
|
# @return [Collection] the collection that the alias points to
|
97
97
|
def self.collection
|
98
98
|
@collection ||= Collection.new(alias_name)
|
99
|
-
rescue Typesense::Error::ObjectNotFound
|
100
|
-
nil
|
101
99
|
end
|
102
100
|
|
103
101
|
# Define the schema for the collection
|
@@ -68,6 +68,35 @@ class Typesensual
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
# Index all records from a model into a new collection, then update the alias to point to it.
|
72
|
+
#
|
73
|
+
# @param index [String] The name of the index to index into
|
74
|
+
# @param model [String] The name of the model to index from
|
75
|
+
# @example
|
76
|
+
# take typesensual:reindex[FooIndex,Foo]
|
77
|
+
def reindex(index:, model:, output: $stdout)
|
78
|
+
index = index.safe_constantize
|
79
|
+
model = model.safe_constantize
|
80
|
+
|
81
|
+
collection = index.create!
|
82
|
+
output.printf(
|
83
|
+
Paint["==> Reindexing %<model>s into %<index>s (Version %<version>s)\n", :bold],
|
84
|
+
model: model.name,
|
85
|
+
index: index.name,
|
86
|
+
version: collection.version
|
87
|
+
)
|
88
|
+
failures = index.index_many(
|
89
|
+
model.ids,
|
90
|
+
collection: collection
|
91
|
+
)
|
92
|
+
|
93
|
+
index.update_alias!(collection)
|
94
|
+
|
95
|
+
failures.each do |failure|
|
96
|
+
output.puts(failure.to_json)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
71
100
|
# Update the alias for an index to point to a specific version
|
72
101
|
#
|
73
102
|
# @param index [String] The name of the index to update
|
@@ -76,7 +105,11 @@ class Typesensual
|
|
76
105
|
# rake typesensual:update_alias[FooIndex,1]
|
77
106
|
def update_alias(index:, version:, output: $stdout)
|
78
107
|
index = index.safe_constantize
|
79
|
-
old_coll =
|
108
|
+
old_coll = begin
|
109
|
+
index.collection
|
110
|
+
rescue Typesense::Error::ObjectNotFound
|
111
|
+
nil
|
112
|
+
end
|
80
113
|
new_coll = index.collection_for(version: version)
|
81
114
|
|
82
115
|
unless new_coll
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Typesensual
|
4
|
+
class Search
|
5
|
+
# Represents a facet returned with search results
|
6
|
+
class Facet
|
7
|
+
attr_reader :key
|
8
|
+
|
9
|
+
def initialize(key, facet)
|
10
|
+
@key = key
|
11
|
+
@facet = facet
|
12
|
+
end
|
13
|
+
|
14
|
+
def count
|
15
|
+
@facet['count']
|
16
|
+
end
|
17
|
+
|
18
|
+
def value
|
19
|
+
@facet['value']
|
20
|
+
end
|
21
|
+
|
22
|
+
def highlighted
|
23
|
+
@facet['highlighted']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -3,8 +3,9 @@
|
|
3
3
|
class Typesensual
|
4
4
|
class Search
|
5
5
|
class Results
|
6
|
-
def initialize(results)
|
6
|
+
def initialize(results, search:)
|
7
7
|
@results = results
|
8
|
+
@search = search
|
8
9
|
end
|
9
10
|
|
10
11
|
def hits
|
@@ -43,12 +44,22 @@ class Typesensual
|
|
43
44
|
current_page + 1 unless last_page?
|
44
45
|
end
|
45
46
|
|
47
|
+
def per_page
|
48
|
+
@results['request_params']['per_page'].to_i
|
49
|
+
end
|
50
|
+
|
46
51
|
def search_time_ms
|
47
52
|
@results['search_time_ms']
|
48
53
|
end
|
49
54
|
|
50
55
|
def total_pages
|
51
|
-
(@results['found'] /
|
56
|
+
(@results['found'] / per_page.to_f).ceil
|
57
|
+
end
|
58
|
+
|
59
|
+
def facets
|
60
|
+
@search.facet_keys.zip(@results['facet_counts']).to_h do |(key, facet)|
|
61
|
+
[key, Facet.new(key, facet)]
|
62
|
+
end
|
52
63
|
end
|
53
64
|
end
|
54
65
|
end
|
data/lib/typesensual/search.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'typesensual/search/facet'
|
3
4
|
require 'typesensual/search/hit'
|
4
5
|
require 'typesensual/search/grouped_hit'
|
5
6
|
require 'typesensual/search/results'
|
@@ -8,6 +9,11 @@ class Typesensual
|
|
8
9
|
class Search
|
9
10
|
include StateHelpers
|
10
11
|
|
12
|
+
# The keys of all the facets (used for re-keying the facets in the results)
|
13
|
+
# @return [Array<String>]
|
14
|
+
# @!visibility private
|
15
|
+
attr_reader :facet_keys
|
16
|
+
|
11
17
|
# Initialize a new search object for a collection
|
12
18
|
#
|
13
19
|
# @param collection [Typesensual::Collection] the Typesensual collection object
|
@@ -21,6 +27,9 @@ class Typesensual
|
|
21
27
|
@sort_by = []
|
22
28
|
@facet_by = []
|
23
29
|
@facet_query = []
|
30
|
+
# this is just used by the Results class to determine names for facets
|
31
|
+
@facet_keys = []
|
32
|
+
@facet_return_parent = []
|
24
33
|
@include_fields = []
|
25
34
|
@exclude_fields = []
|
26
35
|
@group_by = []
|
@@ -41,12 +50,14 @@ class Typesensual
|
|
41
50
|
|
42
51
|
# Set the number of results to return per page
|
43
52
|
# @param count [Integer] the number of results to return per page
|
53
|
+
# @return [self]
|
44
54
|
def per(count)
|
45
55
|
set(per_page: count)
|
46
56
|
end
|
47
57
|
|
48
58
|
# Set the page number to return
|
49
59
|
# @param number [Integer] the page number to return
|
60
|
+
# @return [self]
|
50
61
|
def page(number)
|
51
62
|
set(page: number)
|
52
63
|
end
|
@@ -55,9 +66,12 @@ class Typesensual
|
|
55
66
|
# @param filter [String, Symbol, Hash<String, Symbol>] the filter to add. If a hash is
|
56
67
|
# provided, the keys are the fields and the values are the values to filter by. If a
|
57
68
|
# string is provided, it is added directly as a filter. All filters are ANDed together.
|
69
|
+
# @return [self]
|
58
70
|
def filter(filter)
|
59
71
|
if filter.is_a?(Hash)
|
60
72
|
@filter_by += filter.map { |key, value| "#{key}:#{value}" }
|
73
|
+
elsif filter.is_a?(Array)
|
74
|
+
@filter_by += filter.map(&:to_s)
|
61
75
|
else
|
62
76
|
@filter_by << filter.to_s
|
63
77
|
end
|
@@ -68,6 +82,7 @@ class Typesensual
|
|
68
82
|
# @param value [String, Symbol, Hash<String, Symbol>] the sort to add to the search. If
|
69
83
|
# a hash is provided, the keys are the fields and the values are the directions to sort.
|
70
84
|
# If a string is provided, it is added directly as a sort.
|
85
|
+
# @return [self]
|
71
86
|
def sort(value)
|
72
87
|
if value.is_a?(Hash)
|
73
88
|
@sort_by += value.map { |key, direction| "#{key}:#{direction}" }
|
@@ -77,20 +92,108 @@ class Typesensual
|
|
77
92
|
self
|
78
93
|
end
|
79
94
|
|
80
|
-
# Add a field to facet to the
|
81
|
-
# @
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
95
|
+
# Add a field to facet to the search
|
96
|
+
# @return [self]
|
97
|
+
# @overload facet(facets: Symbol, String, Array)
|
98
|
+
# Basic faceting with just a list of fields
|
99
|
+
# @param facets [String, Symbol, Array<String, Symbol>] the fields to facet on
|
100
|
+
# @example Facet by type
|
101
|
+
# # Generates `facet_by=type`
|
102
|
+
# .facet(:type)
|
103
|
+
# @example Facet by type and year
|
104
|
+
# # Generates `facet_by=type,year`
|
105
|
+
# .facet(['type', 'year'])
|
106
|
+
#
|
107
|
+
# @overload facet(facets: Hash)
|
108
|
+
# Advanced faceting with sort, ranges, return_parent, and query
|
109
|
+
# @param facets [Hash{String, Symbol => String}, Hash{String, Symbol => Hash}] the fields to
|
110
|
+
# facet by and their configuration. If a string is passed as the value, it is used to query
|
111
|
+
# the facet. If a hash is passed, each value is used to configure the facet using the
|
112
|
+
# following options:
|
113
|
+
#
|
114
|
+
# * **`facets[key][:sort]`** (`String, Symbol, Hash{String, Symbol => Symbol}`) — the
|
115
|
+
# field to sort by, and the direction to sort it in. If you pass a string or symbol, it is
|
116
|
+
# used as the sort direction for alphabetical sorting. Typesense only supports sorting by
|
117
|
+
# a single field, and passing more than one field will raise an ArgumentError.
|
118
|
+
# * **`facets[key][:ranges]`** (`Hash{String, Symbol => Range, Array}`) — the ranges to
|
119
|
+
# facet by, for numerical facets. For each key, you can pass a Range or an Array with two
|
120
|
+
# elements. Ranges MUST be end-exclusive and Arrays MUST have two elements, or else an
|
121
|
+
# ArgumentError will be raised.
|
122
|
+
# * **`facets[key][:return_parent]`** (`Boolean`) — if true, the parent object of the field
|
123
|
+
# will be returned, which can be useful for nested fields.
|
124
|
+
# * **`facets[key][:query]`** (`String`) — the query to facet by, equivalent to passing a
|
125
|
+
# string instead of a hash.
|
126
|
+
# @example Facet by category, sorted by category size, and return the parent
|
127
|
+
# # Generates `facet_by=categories.id(categories.size:desc)&facet_return_parent=categories.id`
|
128
|
+
# .facet('categories.id' => { sort: { 'categories.size' => :desc }, return_parent: true })
|
129
|
+
# @example Facet by decade
|
130
|
+
# # Generates `facet_by=year(1990s:[1990,2000],2000s:[2000,2010])`
|
131
|
+
# .facet('year' => { ranges: { '1990s' => 1990...2000, '2000s' => [2000, 2010] })
|
85
132
|
def facet(facets)
|
86
133
|
if facets.is_a?(Hash)
|
87
134
|
facets.each do |key, value|
|
88
|
-
@
|
89
|
-
|
135
|
+
@facet_keys << key.to_s
|
136
|
+
if value.is_a?(String)
|
137
|
+
# Basic facet searching with a string query
|
138
|
+
@facet_by << key.to_s
|
139
|
+
@facet_query << "#{key}:#{value}" if value
|
140
|
+
elsif value.is_a?(Hash)
|
141
|
+
# Advanced faceting with sort, ranges, return_parent, and query
|
142
|
+
facet_string = key.to_s
|
143
|
+
facet_params = {}
|
144
|
+
|
145
|
+
# Sort parameters
|
146
|
+
case value[:sort]
|
147
|
+
when Hash
|
148
|
+
raise ArgumentError, 'Facet sort_by must have one key' if value[:sort].count != 1
|
149
|
+
sort_key, sort_direction = value[:sort].first
|
150
|
+
facet_params[:sort_by] = "#{sort_key}:#{sort_direction}"
|
151
|
+
when Symbol
|
152
|
+
facet_params[:sort_by] = "_alpha:#{value[:sort]}"
|
153
|
+
when String
|
154
|
+
facet_params[:sort_by] = value[:sort]
|
155
|
+
when nil
|
156
|
+
nil
|
157
|
+
else
|
158
|
+
raise ArgumentError, 'Facet sort_by must be a Hash, Symbol, or String'
|
159
|
+
end
|
160
|
+
|
161
|
+
# Range parameters
|
162
|
+
if value[:ranges].is_a?(Hash)
|
163
|
+
ranges = value[:ranges].transform_values do |range|
|
164
|
+
case range
|
165
|
+
when Range
|
166
|
+
raise ArgumentError, 'Facet ranges must exclude end' unless range.exclude_end?
|
167
|
+
"[#{range.begin},#{range.end}]"
|
168
|
+
when Array
|
169
|
+
raise ArgumentError, 'Facet ranges must have two elements' unless range.count == 2
|
170
|
+
"[#{range.first},#{range.last}]"
|
171
|
+
else
|
172
|
+
raise ArgumentError, 'Facet ranges must be a Range or Array'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
facet_params.merge!(ranges)
|
176
|
+
elsif !value[:ranges].nil?
|
177
|
+
raise ArgumentError, 'Facet ranges must be a Hash'
|
178
|
+
end
|
179
|
+
|
180
|
+
# Format facet params
|
181
|
+
unless facet_params.empty?
|
182
|
+
facet_string += "(#{facet_params.map { |k, v| "#{k}:#{v}" }.join(',')})"
|
183
|
+
end
|
184
|
+
|
185
|
+
@facet_return_parent << key.to_s if value[:return_parent]
|
186
|
+
@facet_query << "#{key}:#{value[:query]}" if value[:query]
|
187
|
+
@facet_by << facet_string
|
188
|
+
else
|
189
|
+
@facet_by << key.to_s
|
190
|
+
end
|
90
191
|
end
|
91
192
|
elsif facets.is_a?(Array)
|
193
|
+
@facet_keys += facets.map(&:to_s)
|
92
194
|
@facet_by += facets.map(&:to_s)
|
93
195
|
else
|
196
|
+
@facet_keys << facets.to_s
|
94
197
|
@facet_by << facets.to_s
|
95
198
|
end
|
96
199
|
self
|
@@ -98,6 +201,7 @@ class Typesensual
|
|
98
201
|
|
99
202
|
# Add fields to include in the search result documents
|
100
203
|
# @param fields [String, Symbol, Array<String, Symbol>] the fields to include
|
204
|
+
# @return [self]
|
101
205
|
def include_fields(*fields)
|
102
206
|
@include_fields += fields.map(&:to_s)
|
103
207
|
self
|
@@ -105,11 +209,15 @@ class Typesensual
|
|
105
209
|
|
106
210
|
# Add fields to exclude from the search result documents
|
107
211
|
# @param fields [String, Symbol, Array<String, Symbol>] the fields to exclude
|
212
|
+
# @return [self]
|
108
213
|
def exclude_fields(*fields)
|
109
214
|
@exclude_fields += fields.map(&:to_s)
|
110
215
|
self
|
111
216
|
end
|
112
217
|
|
218
|
+
# Add fields to group the search results by
|
219
|
+
# @param fields [String, Symbol, Array<String, Symbol>] the fields to group by
|
220
|
+
# @return [self]
|
113
221
|
def group_by(*fields)
|
114
222
|
@group_by += fields.map(&:to_s)
|
115
223
|
self
|
@@ -117,6 +225,7 @@ class Typesensual
|
|
117
225
|
|
118
226
|
# Set additional parameters to pass to the search
|
119
227
|
# @param values [Hash] the parameters to set
|
228
|
+
# @return [self]
|
120
229
|
def set(values)
|
121
230
|
@params.merge!(values)
|
122
231
|
self
|
@@ -133,6 +242,7 @@ class Typesensual
|
|
133
242
|
query_by_weights: @query_by_weights&.join(','),
|
134
243
|
sort_by: @sort_by&.join(','),
|
135
244
|
facet_by: @facet_by&.join(','),
|
245
|
+
facet_return_parent: @facet_return_parent&.join(','),
|
136
246
|
facet_query: @facet_query&.join(','),
|
137
247
|
include_fields: @include_fields&.join(','),
|
138
248
|
exclude_fields: @exclude_fields&.join(','),
|
@@ -143,7 +253,9 @@ class Typesensual
|
|
143
253
|
# Load the results from the search query
|
144
254
|
# @return [Typesensual::Search::Results] the results of the search
|
145
255
|
def load
|
146
|
-
|
256
|
+
result = self.class.multi(self).first
|
257
|
+
raise result if result.is_a?(StandardError)
|
258
|
+
result
|
147
259
|
end
|
148
260
|
|
149
261
|
# Perform multiple searches in one request. There are two variants of this method, one which
|
@@ -179,7 +291,9 @@ class Typesensual
|
|
179
291
|
|
180
292
|
# Wrap our results in Result objects
|
181
293
|
wrapped_results = results['results'].map do |result|
|
182
|
-
|
294
|
+
exception = exception_for(result) if result['code']
|
295
|
+
|
296
|
+
exception || Results.new(result, search: self)
|
183
297
|
end
|
184
298
|
|
185
299
|
# If we're doing named searches, re-key the results
|
@@ -189,5 +303,19 @@ class Typesensual
|
|
189
303
|
wrapped_results
|
190
304
|
end
|
191
305
|
end
|
306
|
+
|
307
|
+
# Roughly duplicates the logic from Typesense::ApiCall#custom_exception_klass_for
|
308
|
+
private_class_method def self.exception_for(result)
|
309
|
+
case result['code']
|
310
|
+
when 400 then Typesense::Error::RequestMalformed.new(result['message'])
|
311
|
+
when 401 then Typesense::Error::RequestUnauthorized.new(result['message'])
|
312
|
+
when 404 then Typesense::Error::ObjectNotFound.new(result['message'])
|
313
|
+
when 409 then Typesense::Error::ObjectAlreadyExists.new(result['message'])
|
314
|
+
when 422 then Typesense::Error::ObjectUnprocessable.new(result['message'])
|
315
|
+
when 500..599 then Typesense::Error::ServerError.new(result['message'])
|
316
|
+
when 100..399, nil then nil
|
317
|
+
else Typesense::Error.new(result['message'])
|
318
|
+
end
|
319
|
+
end
|
192
320
|
end
|
193
321
|
end
|
data/lib/typesensual/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typesensual
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Emma Lejeck
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -52,9 +52,9 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.13.0
|
55
|
-
description:
|
55
|
+
description:
|
56
56
|
email:
|
57
|
-
- nuck@kitsu.
|
57
|
+
- nuck@kitsu.app
|
58
58
|
executables: []
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- lib/typesensual/rake_helper.rb
|
81
81
|
- lib/typesensual/schema.rb
|
82
82
|
- lib/typesensual/search.rb
|
83
|
+
- lib/typesensual/search/facet.rb
|
83
84
|
- lib/typesensual/search/grouped_hit.rb
|
84
85
|
- lib/typesensual/search/hit.rb
|
85
86
|
- lib/typesensual/search/results.rb
|
@@ -93,7 +94,7 @@ metadata:
|
|
93
94
|
source_code_uri: https://github.com/hummingbird-me/typesensual
|
94
95
|
changelog_uri: https://github.com/hummingbird-me/typesensual/blob/main/CHANGELOG.md
|
95
96
|
rubygems_mfa_required: 'true'
|
96
|
-
post_install_message:
|
97
|
+
post_install_message:
|
97
98
|
rdoc_options: []
|
98
99
|
require_paths:
|
99
100
|
- lib
|
@@ -109,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
110
|
version: '0'
|
110
111
|
requirements: []
|
111
112
|
rubygems_version: 3.3.26
|
112
|
-
signing_key:
|
113
|
+
signing_key:
|
113
114
|
specification_version: 4
|
114
115
|
summary: A simple, sensual wrapper around Typesense for Ruby
|
115
116
|
test_files: []
|