redi_search 5.0.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/lint.yml +3 -3
  3. data/.github/workflows/tests.yml +8 -5
  4. data/Gemfile +1 -0
  5. data/README.md +57 -58
  6. data/bin/console +8 -4
  7. data/bin/publish +2 -2
  8. data/gemfiles/activerecord_60.gemfile +1 -0
  9. data/gemfiles/activerecord_61.gemfile +1 -0
  10. data/gemfiles/activerecord_70.gemfile +2 -1
  11. data/lib/redi_search/add_field.rb +9 -15
  12. data/lib/redi_search/client.rb +9 -7
  13. data/lib/redi_search/document.rb +6 -11
  14. data/lib/redi_search/index.rb +4 -11
  15. data/lib/redi_search/model.rb +20 -28
  16. data/lib/redi_search/schema/field.rb +15 -1
  17. data/lib/redi_search/schema/geo_field.rb +5 -6
  18. data/lib/redi_search/schema/numeric_field.rb +5 -6
  19. data/lib/redi_search/schema/tag_field.rb +12 -8
  20. data/lib/redi_search/schema/text_field.rb +7 -6
  21. data/lib/redi_search/schema.rb +33 -25
  22. data/lib/redi_search/search/clauses/and.rb +0 -2
  23. data/lib/redi_search/search/clauses/application_clause.rb +0 -2
  24. data/lib/redi_search/search/clauses/boolean.rb +1 -1
  25. data/lib/redi_search/search/clauses/in_order.rb +0 -2
  26. data/lib/redi_search/search/clauses/language.rb +0 -2
  27. data/lib/redi_search/search/clauses/limit.rb +0 -2
  28. data/lib/redi_search/search/clauses/no_content.rb +0 -2
  29. data/lib/redi_search/search/clauses/no_stop_words.rb +0 -2
  30. data/lib/redi_search/search/clauses/or.rb +0 -2
  31. data/lib/redi_search/search/clauses/return.rb +0 -2
  32. data/lib/redi_search/search/clauses/slop.rb +0 -2
  33. data/lib/redi_search/search/clauses/sort_by.rb +0 -2
  34. data/lib/redi_search/search/clauses/verbatim.rb +0 -2
  35. data/lib/redi_search/search/clauses/where.rb +1 -1
  36. data/lib/redi_search/search/clauses/with_scores.rb +0 -2
  37. data/lib/redi_search/search/clauses.rb +0 -16
  38. data/lib/redi_search/search/term.rb +16 -9
  39. data/lib/redi_search/search.rb +0 -6
  40. data/lib/redi_search/spellcheck.rb +2 -6
  41. data/lib/redi_search/validatable.rb +0 -4
  42. data/lib/redi_search/validations/numericality.rb +0 -2
  43. data/lib/redi_search/version.rb +1 -1
  44. data/lib/redi_search.rb +3 -7
  45. data/redi_search.gemspec +8 -5
  46. metadata +17 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 140fad214c11689ac648949c29c17409c96164ca68e9c6cc5cb694b291aa685c
4
- data.tar.gz: 7ba282b0a28eb08c5a8064d3d26afd6c1b97935991f55bd5b69ff50c5a3b7eec
3
+ metadata.gz: 44546188ac7648ecd413eea9c79c93fc76c23009476f585a2bf600e2da4afe3b
4
+ data.tar.gz: eb8b6db657a5f671a8d0da0f69653d97301f8c2d116cfc9427b5105133312495
5
5
  SHA512:
6
- metadata.gz: df96fa21f24f4fec24c66c64b447775a01eb9de86fbf5b30fd028a101363f8036e612d2a2d9b49ed4f09c6dcc14bbcbe7f9a9893be5dcc4dcec7aa4a75db9c95
7
- data.tar.gz: 63c12659be3dc7fdfd790c5f4bab980e970ae5943273c2bda750ba0b43c0ddab50390cb718193130ee7658dd6b6384eed96881619ce49699bb7914c5687643fc
6
+ metadata.gz: adda3ec25f90ea2a4b372549c1d1903a48774b890c9fd589e43ef87c7bccb11f19282f0e5b34df46026c7fffd4e3826ec4d6ef9d1a0216100846f5ece6f1bab7
7
+ data.tar.gz: a1dc85af4e881b0ad63ae54f4b36cbaead28f2558fdf48674d82ef996bd7bc4482f417c92df920ca4480a20ad05fc190c14300c45467b35c91db23b296fa6d0e
@@ -4,17 +4,17 @@ on:
4
4
  pull_request:
5
5
  push:
6
6
  branches:
7
- - master
7
+ - main
8
8
 
9
9
  jobs:
10
10
  lint:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: actions/checkout@v2
14
- - name: Set up Ruby 3.0
14
+ - name: Set up Ruby 3.1
15
15
  uses: ruby/setup-ruby@v1
16
16
  with:
17
- ruby-version: 3.0
17
+ ruby-version: 3.1
18
18
  - name: Install rubocop
19
19
  run: |
20
20
  gem install rubocop rubocop-performance rubocop-minitest rubocop-rake
@@ -4,14 +4,14 @@ on:
4
4
  pull_request:
5
5
  push:
6
6
  branches:
7
- - master
7
+ - main
8
8
 
9
9
  jobs:
10
10
  unit:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- ruby: [ '2.7', '3.0' ]
14
+ ruby: [ '2.7', '3.0', '3.1' ]
15
15
  gemfile: [ 'Gemfile', 'gemfiles/activerecord_60.gemfile', 'gemfiles/activerecord_61.gemfile', 'gemfiles/activerecord_70.gemfile' ]
16
16
  steps:
17
17
  - uses: actions/checkout@v2
@@ -29,17 +29,20 @@ jobs:
29
29
  run: BUNDLE_GEMFILE=${{ matrix.gemfile }} bundle exec rake test:unit
30
30
  integration:
31
31
  runs-on: ubuntu-latest
32
+ strategy:
33
+ matrix:
34
+ redisearch: [ '2.0.14', '2.2.7' ]
32
35
  services:
33
36
  redisearch:
34
- image: redislabs/redisearch:2.0.12
37
+ image: redislabs/redisearch:${{ matrix.redisearch }}
35
38
  ports:
36
39
  - 6379:6379
37
40
  steps:
38
41
  - uses: actions/checkout@v2
39
- - name: Set up Ruby 3.0
42
+ - name: Set up Ruby 3.1
40
43
  uses: ruby/setup-ruby@v1
41
44
  with:
42
- ruby-version: 3.0
45
+ ruby-version: 3.1
43
46
  - name: Install dependencies
44
47
  run: |
45
48
  sudo apt-get install libsqlite3-dev -y
data/Gemfile CHANGED
@@ -7,6 +7,7 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
7
7
  gemspec
8
8
 
9
9
  gem "appraisal", "~> 2.2"
10
+ gem "debug"
10
11
  gem "faker"
11
12
  gem "mocha"
12
13
  gem "rubocop"
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <p align="center">
2
2
  <a href="https://github.com/npezza93/redi_search">
3
- <img src="https://raw.githubusercontent.com/npezza93/redi_search/master/.github/logo.svg?sanitize=true" width="350">
3
+ <img src="https://raw.githubusercontent.com/npezza93/redi_search/main/.github/logo.svg?sanitize=true" width="350">
4
4
  </a>
5
5
  </p>
6
6
 
@@ -103,17 +103,19 @@ defining what a search index is. According to [Swiftype](https://swiftype.com):
103
103
  ## Schema
104
104
 
105
105
  This defines the fields and the properties of those fields in the index. A
106
- schema is a hash, with field names as the keys, and the field type(and options)
107
- as the value. Each field can be one of four types: geo, numeric, tag, or text
108
- and can have many options. A simple example of a schema is:
106
+ schema is a simple DSL. Each field can be one of four types: geo, numeric, tag,
107
+ or text and can have many options. A simple example of a schema is:
109
108
  ```ruby
110
- { first_name: :text, last_name: :text }
109
+ RediSearch::Schema.new do
110
+ text_field :first_name
111
+ text_field :last_name
112
+ end
111
113
  ```
112
114
 
113
115
  The supported options for each type are as follows:
114
116
 
115
117
  ##### Text field
116
- With no options: `{ name: :text }`
118
+ With no options: `text_field :name`
117
119
 
118
120
  <details>
119
121
  <summary>Options</summary>
@@ -122,7 +124,7 @@ With no options: `{ name: :text }`
122
124
  <b>weight</b> (default: 1.0)
123
125
  <ul>
124
126
  <li>Declares the importance of this field when calculating result accuracy. This is a multiplication factor.</li>
125
- <li>Ex: <code>{ name: { text: { weight: 2 } } }</code></li>
127
+ <li>Ex: <code>text_field :name, weight: 2</code></li>
126
128
  </ul>
127
129
  </li>
128
130
  <li>
@@ -137,7 +139,7 @@ With no options: `{ name: :text }`
137
139
  </ul>
138
140
  </li>
139
141
  <li>
140
- Ex: <code>{ name: { text: { phonetic: 'dm:en' } } }</code>
142
+ Ex: <code>text_field :name, phonetic: 'dm:en'</code>
141
143
  </li>
142
144
  </ul>
143
145
  </li>
@@ -145,28 +147,28 @@ With no options: `{ name: :text }`
145
147
  <b>sortable</b> (default: false)
146
148
  <ul>
147
149
  <li>Allows the user to later sort the results by the value of this field (this adds memory overhead so do not declare it on large text fields).</li>
148
- <li>Ex: <code>{ name: { text: { sortable: true } } }</code></li>
150
+ <li>Ex: <code>text_field :name, sortable: true</code></li>
149
151
  </ul>
150
152
  </li>
151
153
  <li>
152
154
  <b>no_index</b> (default: false)
153
155
  <ul>
154
156
  <li>Field will not be indexed. This is useful in conjunction with <code>sortable</code>, to create fields whose update using PARTIAL will not cause full reindexing of the document. If a field has <code>no_index</code> and doesn't have <code>sortable</code>, it will just be ignored by the index.</li>
155
- <li>Ex: <code>{ name: { text: { no_index: true } } }</code></li>
157
+ <li>Ex: <code>text_field :name, no_index: true</code></li>
156
158
  </ul>
157
159
  </li>
158
160
  <li>
159
161
  <b>no_stem</b> (default: false)
160
162
  <ul>
161
163
  <li>Disable stemming when indexing its values. This may be ideal for things like proper names.</li>
162
- <li>Ex: <code>{ name: { text: { no_stem: true } } }</code></li>
164
+ <li>Ex: <code>text_feidl :name, no_stem: true</code></li>
163
165
  </ul>
164
166
  </li>
165
167
  </ul>
166
168
  </details>
167
169
 
168
170
  ##### Numeric field
169
- With no options: `{ price: :numeric }`
171
+ With no options: `numeric_field :price`
170
172
 
171
173
  <details>
172
174
  <summary>Options</summary>
@@ -175,21 +177,21 @@ With no options: `{ price: :numeric }`
175
177
  <b>sortable</b> (default: false)
176
178
  <ul>
177
179
  <li>Allows the user to later sort the results by the value of this field (this adds memory overhead so do not declare it on large text fields).</li>
178
- <li>Ex: <code>{ id: { numeric: { sortable: true } } }</code></li>
180
+ <li>Ex: <code>numeric_field :id, sortable: true</code></li>
179
181
  </ul>
180
182
  </li>
181
183
  <li>
182
184
  <b>no_index</b> (default: false)
183
185
  <ul>
184
186
  <li>Field will not be indexed. This is useful in conjunction with <code>sortable</code>, to create fields whose update using PARTIAL will not cause full reindexing of the document. If a field has <code>no_index</code> and doesn't have <code>sortable</code>, it will just be ignored by the index.</li>
185
- <li>Ex: <code>{ id: { numeric: { no_index: true } } }</code></li>
187
+ <li>Ex: <code>numeric_field :id, no_index: true</code></li>
186
188
  </ul>
187
189
  </li>
188
190
  </ul>
189
191
  </details>
190
192
 
191
193
  ##### Tag field
192
- With no options: `{ tag: :tag }`
194
+ With no options: `tag_field :tag`
193
195
 
194
196
  <details>
195
197
  <summary>Options</summary>
@@ -198,28 +200,28 @@ With no options: `{ tag: :tag }`
198
200
  <b>sortable</b> (default: false)
199
201
  <ul>
200
202
  <li>Allows the user to later sort the results by the value of this field (this adds memory overhead so do not declare it on large text fields).</li>
201
- <li>Ex: <code>{ tag: { tag: { sortable: true } } }</code></li>
203
+ <li>Ex: <code>tag_field :tag, sortable: true</code></li>
202
204
  </ul>
203
205
  </li>
204
206
  <li>
205
207
  <b>no_index</b> (default: false)
206
208
  <ul>
207
209
  <li>Field will not be indexed. This is useful in conjunction with <code>sortable</code>, to create fields whose update using PARTIAL will not cause full reindexing of the document. If a field has <code>no_index</code> and doesn't have <code>sortable</code>, it will just be ignored by the index.</li>
208
- <li>Ex: <code>{ tag: { tag: { no_index: true } } }</code></li>
210
+ <li>Ex: <code>tag_field :tag, no_index: true</code></li>
209
211
  </ul>
210
212
  </li>
211
213
  <li>
212
214
  <b>separator</b> (default: ",")
213
215
  <ul>
214
216
  <li>Indicates how the text contained in the field is to be split into individual tags. The default is ,. The value must be a single character.</li>
215
- <li>Ex: <code>{ tag: { tag: { separator: ',' } } }</code></li>
217
+ <li>Ex: <code>tag_field :tag, separator: ','</code></li>
216
218
  </ul>
217
219
  </li>
218
220
  </ul>
219
221
  </details>
220
222
 
221
223
  ##### Geo field
222
- With no options: `{ place: :geo }`
224
+ With no options: `geo_field :place`
223
225
 
224
226
  <details>
225
227
  <summary>Options</summary>
@@ -228,14 +230,14 @@ With no options: `{ place: :geo }`
228
230
  <b>sortable</b> (default: false)
229
231
  <ul>
230
232
  <li>Allows the user to later sort the results by the value of this field (this adds memory overhead so do not declare it on large text fields).</li>
231
- <li>Ex: <code>{ place: { geo: { sortable: true } } }</code></li>
233
+ <li>Ex: <code>geo_field :place, sortable: true</code></li>
232
234
  </ul>
233
235
  </li>
234
236
  <li>
235
237
  <b>no_index</b> (default: false)
236
238
  <ul>
237
239
  <li>Field will not be indexed. This is useful in conjunction with <code>sortable</code>, to create fields whose update using PARTIAL will not cause full reindexing of the document. If a field has <code>no_index</code> and doesn't have <code>sortable</code>, it will just be ignored by the index.</li>
238
- <li>Ex: <code>{ place: { geo: { no_index: true } } }</code></li>
240
+ <li>Ex: <code>geo_field :place, no_index: true</code></li>
239
241
  </ul>
240
242
  </li>
241
243
  </ul>
@@ -250,12 +252,10 @@ You can fetch a `Document` using `.get` class methods.
250
252
  given `document_id`.
251
253
 
252
254
  You can also make a `Document` instance using the
253
- `.for_object(index, record, serializer: nil, only: [])` class method. It takes
255
+ `.for_object(index, record, only: [])` class method. It takes
254
256
  an `Index` instance and a Ruby object. That object must respond to all the
255
- fields specified in the `Index`'s `Schema` or pass a serializer class that
256
- accepts the object and responds to all the fields specified in the `Index`'s
257
- `Schema`. `only` accepts an array of fields from the schema and limits the
258
- fields that are passed to the `Document`.
257
+ fields specified in the `Index`'s `Schema`. `only` accepts an array of fields
258
+ from the schema and limits the fields that are passed to the `Document`.
259
259
 
260
260
  Once you have an instance of a `Document`, it responds to all the fields
261
261
  specified in the `Index`'s `Schema` as methods and `document_id`. `document_id`
@@ -271,10 +271,12 @@ Finally there is a `#del` method that will remove the `Document` from the
271
271
  ## Index
272
272
 
273
273
  To initialize an `Index`, pass the name of the `Index` as a string or symbol
274
- and the `Schema`.
274
+ and the `Schema` block.
275
275
 
276
276
  ```ruby
277
- RediSearch::Index.new(name_of_index, schema)
277
+ RediSearch::Index.new(name_of_index) do
278
+ text_field :foobar
279
+ end
278
280
  ```
279
281
 
280
282
  #### Available Commands
@@ -330,8 +332,10 @@ RediSearch::Index.new(name_of_index, schema)
330
332
  - Removes a `Document` from the `Index`.
331
333
  - `document_count`
332
334
  - Returns the number of `Document`s in the `Index`
333
- - `add_field(field_name, schema)`
334
- - Adds a new field to the `Index`. Ex: `index.add_field(:first_name, text: { phonetic: "dm:en" })`
335
+ - `add_field(name, type, **options, &block)`
336
+ - Adds a new field to the `Index`.
337
+ - The block and options are optional.
338
+ - Ex: `index.add_field(:first_name, :text, phonetic: "dm:en")`
335
339
  - `reindex(documents, recreate: false)`
336
340
  - If `recreate` is `true` the `Index` will be dropped and recreated
337
341
 
@@ -343,7 +347,7 @@ be chained together. When searching, an array of `Document`s is returned
343
347
  which has public reader methods for all the schema fields.
344
348
 
345
349
  ```ruby
346
- main ❯ index = RediSearch::Index.new("user_idx", name: { text: { phonetic: "dm:en" } })
350
+ main ❯ index = RediSearch::Index.new("user_idx") { text_field :name, phonetic: "dm:en" }
347
351
  main ❯ index.add RediSearch::Document.for_object(index, User.new("10039", "Gene", "Volkman"))
348
352
  main ❯ index.add RediSearch::Document.for_object(index, User.new("9998", "Jeannie", "Ledner"))
349
353
  main ❯ index.search("john")
@@ -473,7 +477,7 @@ returns an array where each element contains suggestions for each search term
473
477
  and a normalized score based on its occurrences in the index.
474
478
 
475
479
  ```ruby
476
- main ❯ index = RediSearch::Index.new("user_idx", name: { text: { phonetic: "dm:en" } })
480
+ main ❯ index = RediSearch::Index.new("user_idx") { text_field :name, phonetic: "dm:en" }
477
481
  main ❯ index.spellcheck("jimy")
478
482
  RediSearch (1.1ms) FT.SPELLCHECK user_idx jimy DISTANCE 1
479
483
  => [#<RediSearch::Spellcheck::Result:0x00007f805591c670
@@ -495,10 +499,10 @@ keyword argument from inside your model. Ex:
495
499
 
496
500
  ```ruby
497
501
  class User < ApplicationRecord
498
- redi_search schema: {
499
- first: { text: { phonetic: "dm:en" } },
500
- last: { text: { phonetic: "dm:en" } }
501
- }
502
+ redi_search do
503
+ text_field :first, phonetic: "dm:en"
504
+ text_field :last, phonetic: "dm:en"
505
+ end
502
506
  end
503
507
  ```
504
508
 
@@ -515,21 +519,16 @@ similarly to `RediSearch::Index#reindex`. Some of the differences include:
515
519
  particular field.
516
520
 
517
521
 
518
- The `redi_search` class method also takes an optional `serializer` argument
519
- which takes the class name of a serializer. The serializer must respond to all
520
- the fields in a schema as methods. We don't serialize to a JSON object since
521
- RediSearch doesn't serialize documents that way.
522
+ While defining the schema you can optionally pass it a block. If no block is
523
+ passed the `name` will called on the model to get the value. If a block is
524
+ passed the value for the field is obtained through calling the block.
522
525
 
523
526
  ```ruby
524
527
  class User < ApplicationRecord
525
- redi_search schema: {
526
- name: { text: { phonetic: "dm:en" } }
527
- }, serializer: UserSerializer
528
- end
529
-
530
- class UserSerializer < SimpleDelegator
531
- def name
532
- "#{first_name} #{last_name}"
528
+ redi_search do
529
+ text_field :name do
530
+ "#{first_name} #{last_name}"
531
+ end
533
532
  end
534
533
  end
535
534
  ```
@@ -553,13 +552,13 @@ optional `index_prefix` argument which gets prepended to the index name:
553
552
 
554
553
  ```ruby
555
554
  class User < ApplicationRecord
556
- redi_search schema: {
557
- first: { text: { phonetic: "dm:en" } },
558
- last: { text: { phonetic: "dm:en" } }
559
- }, index_prefix: 'prefix'
555
+ redi_search index_prefix: 'prefix' do
556
+ text_field :first, phonetic: "dm:en"
557
+ text_field :last, phonetic: "dm:en"
558
+ end
560
559
  end
561
560
 
562
- User.redi_search_index.name
561
+ User.search_index.name
563
562
  # => prefix_users_development
564
563
  ```
565
564
 
@@ -568,13 +567,13 @@ after creating and updating and will be removed from the `Index` upon
568
567
  destruction.
569
568
 
570
569
  There are a few more convenience methods that are publicly available:
571
- - `redi_search_document`
570
+ - `search_document`
572
571
  - Returns the record as a `RediSearch::Document` instance
573
- - `redi_search_delete_document`
572
+ - `remove_from_index`
574
573
  - Removes the record from the `Index`
575
- - `redi_search_add_document`
574
+ - `add_to_index`
576
575
  - Adds the record to the `Index`
577
- - `redi_search_index`
576
+ - `search_index`
578
577
  - Returns the `RediSearch::Index` instance
579
578
 
580
579
 
@@ -608,4 +607,4 @@ The gem is available as open source under the terms of the
608
607
 
609
608
  Everyone interacting in the RediSearch project’s codebases, issue trackers, chat
610
609
  rooms and mailing lists is expected to follow the [code of
611
- conduct](https://github.com/npezza93/redi_search/blob/master/CODE_OF_CONDUCT.md).
610
+ conduct](https://github.com/npezza93/redi_search/blob/main/CODE_OF_CONDUCT.md).
data/bin/console CHANGED
@@ -19,10 +19,14 @@ ActiveRecord::Migration.create_table :users do |t|
19
19
  end
20
20
 
21
21
  class User < ActiveRecord::Base
22
- redi_search schema: {
23
- first: { text: { phonetic: "dm:en" } },
24
- last: { text: { phonetic: "dm:en" } }
25
- }
22
+ redi_search do
23
+ text_field :first, phonetic: "dm:en"
24
+ text_field :last, phonetic: "dm:en"
25
+ tag_field :tags
26
+ text_field :name, phonetic: "dm:en" do
27
+ "#{first} #{last}"
28
+ end
29
+ end
26
30
  end
27
31
 
28
32
  def seed_users(count = 10_000)
data/bin/publish CHANGED
@@ -8,7 +8,7 @@ require_relative "../lib/redi_search/version"
8
8
  # path to your application root.
9
9
  APP_ROOT = Pathname.new File.expand_path("..", __dir__)
10
10
  MASTER_CHECK = <<~MASTER_CHECK
11
- if [ $(git symbolic-ref --short -q HEAD) != 'master' ];
11
+ if [ $(git symbolic-ref --short -q HEAD) != 'main' ];
12
12
  then exit 1;
13
13
  fi
14
14
  MASTER_CHECK
@@ -20,7 +20,7 @@ end
20
20
 
21
21
  abort("\n== Version Type incorrect ==") unless VERSION_TYPES.include?(ARGV[0])
22
22
 
23
- abort("\n== Not on master") unless system(MASTER_CHECK)
23
+ abort("\n== Not on main") unless system(MASTER_CHECK)
24
24
 
25
25
  current_version = RediSearch::VERSION.split(".").map(&:to_i)
26
26
 
@@ -3,6 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal", "~> 2.2"
6
+ gem "debug"
6
7
  gem "faker"
7
8
  gem "mocha"
8
9
  gem "rubocop"
@@ -3,6 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal", "~> 2.2"
6
+ gem "debug"
6
7
  gem "faker"
7
8
  gem "mocha"
8
9
  gem "rubocop"
@@ -3,6 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal", "~> 2.2"
6
+ gem "debug"
6
7
  gem "faker"
7
8
  gem "mocha"
8
9
  gem "rubocop"
@@ -10,6 +11,6 @@ gem "rubocop-minitest"
10
11
  gem "rubocop-performance"
11
12
  gem "simplecov"
12
13
  gem "sqlite3"
13
- gem "activerecord", "~> 7.0.0.alpha1"
14
+ gem "activerecord", "~> 7.0.1"
14
15
 
15
16
  gemspec path: "../"
@@ -2,16 +2,18 @@
2
2
 
3
3
  module RediSearch
4
4
  class AddField
5
- def initialize(index, field_name, schema)
6
- @index = index
7
- @field_name = field_name
8
- @raw_schema = schema
5
+ def initialize(index, name, type, **options, &block)
6
+ @index = index
7
+ @name = name
8
+ @type = type
9
+ @options = options
10
+ @block = block
9
11
  end
10
12
 
11
13
  def call!
12
- index.schema.add_field(field_name, raw_schema)
14
+ field = index.schema.add_field(name, type, **options, &block)
13
15
 
14
- RediSearch.client.call!(*command).ok?
16
+ RediSearch.client.call!("ALTER", index.name, "SCHEMA", "ADD", *field).ok?
15
17
  end
16
18
 
17
19
  def call
@@ -22,14 +24,6 @@ module RediSearch
22
24
 
23
25
  private
24
26
 
25
- attr_reader :index, :field_name, :raw_schema
26
-
27
- def command
28
- ["ALTER", index.name, "SCHEMA", "ADD", *field_schema]
29
- end
30
-
31
- def field_schema
32
- @field_schema ||= Schema.make_field(field_name, raw_schema).to_a
33
- end
27
+ attr_reader :index, :name, :type, :options, :block
34
28
  end
35
29
  end
@@ -3,8 +3,6 @@
3
3
  require "redis"
4
4
  require "active_support/notifications"
5
5
 
6
- require "redi_search/client/response"
7
-
8
6
  module RediSearch
9
7
  class Client
10
8
  def initialize(redis = Redis.new)
@@ -20,9 +18,9 @@ module RediSearch
20
18
  end
21
19
 
22
20
  def multi
23
- Response.new(redis.multi do
21
+ Response.new(redis.multi do |pipeline|
24
22
  instrument("pipeline", query: ["begin pipeline"])
25
- capture_pipeline { yield }
23
+ capture_pipeline(pipeline) { yield }
26
24
  instrument("pipeline", query: ["finish pipeline"])
27
25
  end)
28
26
  end
@@ -32,14 +30,18 @@ module RediSearch
32
30
  attr_reader :redis
33
31
  attr_accessor :pipeline
34
32
 
35
- def capture_pipeline
36
- self.pipeline = true
33
+ def capture_pipeline(pipeline)
34
+ self.pipeline = pipeline
37
35
  yield
38
36
  self.pipeline = false
39
37
  end
40
38
 
41
39
  def send_command(command, *params)
42
- Response.new(redis.call(command, *params))
40
+ if pipeline
41
+ Response.new(pipeline.call(command, *params))
42
+ else
43
+ Response.new(redis.call(command, *params))
44
+ end
43
45
  end
44
46
 
45
47
  def instrument(action, payload, &block)
@@ -1,23 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "redi_search/document/display"
4
- require "redi_search/document/finder"
5
-
6
3
  module RediSearch
7
4
  class Document
8
5
  include Display
9
6
 
10
7
  class << self
11
- def for_object(index, record, serializer: nil, only: [])
12
- object_to_serialize = serializer&.new(record) || record
13
-
14
- field_values = index.schema.fields.map(&:name).filter_map do |field|
15
- next unless only.empty? || only.include?(field)
8
+ def for_object(index, record, only: [])
9
+ field_values = index.schema.fields.filter_map do |field|
10
+ next unless only.empty? || only.include?(field.name)
16
11
 
17
- [field.to_s, object_to_serialize.public_send(field)]
12
+ [field.name.to_s, field.serialize(record)]
18
13
  end.to_h
19
14
 
20
- new(index, object_to_serialize.id, field_values)
15
+ new(index, record.id, field_values)
21
16
  end
22
17
 
23
18
  def get(index, document_id)
@@ -48,7 +43,7 @@ module RediSearch
48
43
 
49
44
  def redis_attributes
50
45
  attributes.flat_map do |field, value|
51
- [field, index.schema[field.to_sym].serialize(value)]
46
+ [field, index.schema[field.to_sym].coerce(value)]
52
47
  end
53
48
  end
54
49
 
@@ -1,19 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "redi_search/hset"
4
- require "redi_search/create"
5
- require "redi_search/schema"
6
- require "redi_search/search"
7
- require "redi_search/spellcheck"
8
- require "redi_search/add_field"
9
-
10
3
  module RediSearch
11
4
  class Index
12
5
  attr_reader :name, :schema, :model
13
6
 
14
- def initialize(name, schema, model = nil)
7
+ def initialize(name, model = nil, &schema)
15
8
  @name = name.to_s
16
- @schema = Schema.new(schema)
9
+ @schema = Schema.new(&schema)
17
10
  @model = model
18
11
  end
19
12
 
@@ -94,8 +87,8 @@ module RediSearch
94
87
  info.num_docs.to_i
95
88
  end
96
89
 
97
- def add_field(field_name, schema)
98
- AddField.new(self, field_name, schema).call!
90
+ def add_field(name, type, **options, &block)
91
+ AddField.new(self, name, type, **options, &block).call!
99
92
  end
100
93
 
101
94
  private