stretchy-model 0.3.0 → 0.4.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 +21 -10
- data/Rakefile +92 -0
- data/lib/stretchy/attributes/transformers/keyword_transformer.rb +85 -0
- data/lib/stretchy/attributes/type/keyword.rb +11 -0
- data/lib/stretchy/attributes.rb +10 -0
- data/lib/stretchy/querying.rb +6 -5
- data/lib/stretchy/relation.rb +3 -3
- data/lib/stretchy/relations/aggregation_methods.rb +758 -0
- data/lib/stretchy/relations/finder_methods.rb +21 -3
- data/lib/stretchy/relations/merger.rb +6 -6
- data/lib/stretchy/relations/query_builder.rb +23 -9
- data/lib/stretchy/relations/query_methods.rb +10 -36
- data/lib/stretchy/utils.rb +21 -0
- data/lib/stretchy/version.rb +1 -3
- data/lib/stretchy.rb +21 -9
- metadata +35 -3
@@ -9,7 +9,15 @@ module Stretchy
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def first!
|
12
|
-
|
12
|
+
spawned = spawn
|
13
|
+
if spawned.order_values.length.zero?
|
14
|
+
spawn.sort(Hash[default_sort_key, :asc]).spawn.size(1)
|
15
|
+
elsif spawned.order_values.length >= 1
|
16
|
+
first_order_value = spawned.order_values.shift
|
17
|
+
new_direction = Hash[first_order_value.keys.first, :asc]
|
18
|
+
spawned.order_values.unshift(new_direction)
|
19
|
+
spawned.size(1)
|
20
|
+
end
|
13
21
|
self
|
14
22
|
end
|
15
23
|
|
@@ -19,7 +27,15 @@ module Stretchy
|
|
19
27
|
end
|
20
28
|
|
21
29
|
def last!
|
22
|
-
|
30
|
+
spawned = spawn
|
31
|
+
if spawned.order_values.length.zero?
|
32
|
+
spawn.sort(Hash[default_sort_key, :desc]).spawn.size(1)
|
33
|
+
elsif spawned.order_values.length >= 1
|
34
|
+
first_order_value = spawned.order_values.shift
|
35
|
+
new_direction = Hash[first_order_value.keys.first, :desc]
|
36
|
+
spawned.order_values.unshift(new_direction)
|
37
|
+
spawned.size(1)
|
38
|
+
end
|
23
39
|
self
|
24
40
|
end
|
25
41
|
|
@@ -31,7 +47,9 @@ module Stretchy
|
|
31
47
|
def count!
|
32
48
|
@values[:count] = true
|
33
49
|
@values.delete(:size)
|
34
|
-
spawn
|
50
|
+
spawned = spawn
|
51
|
+
spawned.order_values.clear
|
52
|
+
spawned.results
|
35
53
|
end
|
36
54
|
|
37
55
|
end
|
@@ -50,7 +50,7 @@ module Stretchy
|
|
50
50
|
@other = other
|
51
51
|
end
|
52
52
|
|
53
|
-
NORMAL_VALUES = [:where, :first, :last, :
|
53
|
+
NORMAL_VALUES = [:where, :first, :last, :filter_query]
|
54
54
|
|
55
55
|
def normal_values
|
56
56
|
NORMAL_VALUES
|
@@ -67,7 +67,7 @@ module Stretchy
|
|
67
67
|
unless value.nil? || (value.blank? && false != value)
|
68
68
|
if name == :select
|
69
69
|
relation._select!(*value)
|
70
|
-
elsif name == :
|
70
|
+
elsif name == :filter_query
|
71
71
|
values.each do |v|
|
72
72
|
relation.send("#{name}!", v.first, v.last)
|
73
73
|
end
|
@@ -114,19 +114,19 @@ module Stretchy
|
|
114
114
|
lhs_wheres = relation.where_values
|
115
115
|
rhs_wheres = values[:where] || []
|
116
116
|
|
117
|
-
lhs_filters = relation.
|
118
|
-
rhs_filters = values[:
|
117
|
+
lhs_filters = relation.filter_query_values
|
118
|
+
rhs_filters = values[:filter_query] || []
|
119
119
|
|
120
120
|
removed, kept = partition_overwrites(lhs_wheres, rhs_wheres)
|
121
121
|
|
122
122
|
where_values = kept + rhs_wheres
|
123
123
|
|
124
124
|
filters_removed, filters_kept = partition_overwrites(lhs_wheres, rhs_wheres)
|
125
|
-
|
125
|
+
filter_query_values = rhs_filters
|
126
126
|
|
127
127
|
|
128
128
|
relation.where_values = where_values.empty? ? nil : where_values
|
129
|
-
relation.
|
129
|
+
relation.filter_query_values = filter_query_values.empty? ? nil : filter_query_values
|
130
130
|
|
131
131
|
if values[:reordering]
|
132
132
|
# override any order specified in the original relation
|
@@ -2,9 +2,10 @@ module Stretchy
|
|
2
2
|
module Relations
|
3
3
|
class QueryBuilder
|
4
4
|
|
5
|
-
attr_reader :structure, :values
|
5
|
+
attr_reader :structure, :values, :attribute_types
|
6
6
|
|
7
|
-
def initialize(values)
|
7
|
+
def initialize(values, attribute_types = nil)
|
8
|
+
@attribute_types = attribute_types
|
8
9
|
@structure = Jbuilder.new ignore_nil: true
|
9
10
|
@values = values
|
10
11
|
end
|
@@ -14,7 +15,7 @@ module Stretchy
|
|
14
15
|
end
|
15
16
|
|
16
17
|
def filters
|
17
|
-
values[:
|
18
|
+
values[:filter_query]
|
18
19
|
end
|
19
20
|
|
20
21
|
def or_filters
|
@@ -58,7 +59,7 @@ module Stretchy
|
|
58
59
|
end
|
59
60
|
|
60
61
|
def query_filters
|
61
|
-
values[:
|
62
|
+
values[:filter_query]
|
62
63
|
end
|
63
64
|
|
64
65
|
def search_options
|
@@ -149,7 +150,7 @@ module Stretchy
|
|
149
150
|
end
|
150
151
|
|
151
152
|
def build_sort
|
152
|
-
structure.sort sort.
|
153
|
+
structure.sort sort.map { |arg| keyword_transformer.transform(arg) }.flatten
|
153
154
|
end
|
154
155
|
|
155
156
|
def build_highlights
|
@@ -165,7 +166,7 @@ module Stretchy
|
|
165
166
|
def build_aggregations
|
166
167
|
structure.aggregations do
|
167
168
|
aggregations.each do |agg|
|
168
|
-
structure.set! agg[:name], aggregation(agg[:name], agg[:args])
|
169
|
+
structure.set! agg[:name], aggregation(agg[:name], keyword_transformer.transform(agg[:args], :name))
|
169
170
|
end
|
170
171
|
end
|
171
172
|
end
|
@@ -199,13 +200,23 @@ module Stretchy
|
|
199
200
|
def as_must(q)
|
200
201
|
_must = []
|
201
202
|
q.each do |arg|
|
202
|
-
|
203
|
-
|
204
|
-
|
203
|
+
case arg
|
204
|
+
when Hash
|
205
|
+
arg = keyword_transformer.transform(arg)
|
206
|
+
arg.each_pair do |k,v|
|
207
|
+
# If v is an array, we build a terms query otherwise a term query
|
208
|
+
_must << (v.is_a?(Array) ? {terms: Hash[k,v]} : {term: Hash[k,v]})
|
209
|
+
end
|
210
|
+
when String
|
211
|
+
_must << {term: Hash[[arg.split(/:/).collect(&:strip)]]}
|
212
|
+
when Array
|
213
|
+
_must << arg.first
|
214
|
+
end
|
205
215
|
end
|
206
216
|
_must.length == 1 ? _must.first : _must
|
207
217
|
end
|
208
218
|
|
219
|
+
|
209
220
|
def as_query_string(q)
|
210
221
|
_and = []
|
211
222
|
|
@@ -260,6 +271,9 @@ module Stretchy
|
|
260
271
|
end
|
261
272
|
end
|
262
273
|
|
274
|
+
def keyword_transformer
|
275
|
+
@keyword_transformer ||= Stretchy::Attributes::Transformers::KeywordTransformer.new(@attribute_types)
|
276
|
+
end
|
263
277
|
end
|
264
278
|
end
|
265
279
|
end
|
@@ -15,7 +15,7 @@ module Stretchy
|
|
15
15
|
:query_string,
|
16
16
|
:aggregation,
|
17
17
|
:search_option,
|
18
|
-
:
|
18
|
+
:filter_query,
|
19
19
|
:or_filter,
|
20
20
|
:extending,
|
21
21
|
:skip_callbacks
|
@@ -308,7 +308,7 @@ module Stretchy
|
|
308
308
|
|
309
309
|
|
310
310
|
|
311
|
-
# @deprecated in elasticsearch 7.x+ use {#
|
311
|
+
# @deprecated in elasticsearch 7.x+ use {#filter_query} instead
|
312
312
|
def or_filter(name, options = {}, &block)
|
313
313
|
spawn.or_filter!(name, options, &block)
|
314
314
|
end
|
@@ -322,53 +322,27 @@ module Stretchy
|
|
322
322
|
#
|
323
323
|
# This method supports all filters supported by Elasticsearch.
|
324
324
|
#
|
325
|
-
# @overload
|
325
|
+
# @overload filter_query(type, opts)
|
326
326
|
# @param type [Symbol] the type of filter to add (:range, :term, etc.)
|
327
327
|
# @param opts [Hash] a hash containing the attribute and value to filter by
|
328
328
|
#
|
329
329
|
# @example
|
330
|
-
# Model.
|
331
|
-
# Model.
|
330
|
+
# Model.filter_query(:range, age: {gte: 30})
|
331
|
+
# Model.filter_query(:term, color: :blue)
|
332
332
|
#
|
333
333
|
# @return [Stretchy::Relation] a new relation, which reflects the filter
|
334
|
-
def
|
335
|
-
spawn.
|
334
|
+
def filter_query(name, options = {}, &block)
|
335
|
+
spawn.filter_query!(name, options, &block)
|
336
336
|
end
|
337
337
|
|
338
|
-
def
|
339
|
-
self.
|
338
|
+
def filter_query!(name, options = {}, &block) # :nodoc:
|
339
|
+
self.filter_query_values += [{name: name, args: options}]
|
340
340
|
self
|
341
341
|
end
|
342
342
|
|
343
343
|
|
344
344
|
|
345
|
-
# Adds an aggregation to the query.
|
346
|
-
#
|
347
|
-
# @param name [Symbol, String] the name of the aggregation
|
348
|
-
# @param options [Hash] a hash of options for the aggregation
|
349
|
-
# @param block [Proc] an optional block to further configure the aggregation
|
350
|
-
#
|
351
|
-
# @example
|
352
|
-
# Model.aggregation(:avg_price, field: :price)
|
353
|
-
# Model.aggregation(:price_ranges) do
|
354
|
-
# range field: :price, ranges: [{to: 100}, {from: 100, to: 200}, {from: 200}]
|
355
|
-
# end
|
356
|
-
#
|
357
|
-
# Aggregation results are available in the `aggregations` method of the results under name provided in the aggregation.
|
358
|
-
#
|
359
|
-
# @example
|
360
|
-
# results = Model.where(color: :blue).aggregation(:avg_price, field: :price)
|
361
|
-
# results.aggregations.avg_price
|
362
|
-
#
|
363
|
-
# @return [Stretchy::Relation] a new relation
|
364
|
-
def aggregation(name, options = {}, &block)
|
365
|
-
spawn.aggregation!(name, options, &block)
|
366
|
-
end
|
367
345
|
|
368
|
-
def aggregation!(name, options = {}, &block) # :nodoc:
|
369
|
-
self.aggregation_values += [{name: name, args: assume_keyword_field(options)}]
|
370
|
-
self
|
371
|
-
end
|
372
346
|
|
373
347
|
|
374
348
|
|
@@ -430,7 +404,7 @@ module Stretchy
|
|
430
404
|
#
|
431
405
|
# @return [ActiveRecord::Relation] a new relation, which reflects the exists filter
|
432
406
|
def has_field(field)
|
433
|
-
spawn.
|
407
|
+
spawn.filter_query(:exists, {field: field})
|
434
408
|
end
|
435
409
|
|
436
410
|
|
data/lib/stretchy/utils.rb
CHANGED
@@ -2,6 +2,27 @@ module Stretchy
|
|
2
2
|
module Utils
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
+
concerning :ConsoleMethods do
|
6
|
+
def reload!
|
7
|
+
Stretchy.loader.reload
|
8
|
+
end
|
9
|
+
|
10
|
+
def banner
|
11
|
+
banner = <<~BANNER
|
12
|
+
|
13
|
+
d8b
|
14
|
+
d8P d8P ?88
|
15
|
+
d888888P d888888P 88b
|
16
|
+
.d888b, ?88' 88bd88b d8888b ?88' d8888b 888888b ?88 d8P
|
17
|
+
?8b, 88P 88P' `d8b_,dP 88P d8P' `P 88P `?8bd88 88
|
18
|
+
`?8b 88b d88 88b 88b 88b d88 88P?8( d88
|
19
|
+
`?888P' `?8b d88' `?888P' `?8b `?888P'd88' 88b`?88P'?8b
|
20
|
+
)88
|
21
|
+
,d8P
|
22
|
+
`?888P'
|
23
|
+
BANNER
|
24
|
+
end
|
25
|
+
end
|
5
26
|
|
6
27
|
def self.to_curl(klass, arguments = {}, end_point = "_search")
|
7
28
|
host = klass.gateway.client.transport.transport.hosts&.first || klass.gateway.client.transport.transport.options[:url]
|
data/lib/stretchy/version.rb
CHANGED
data/lib/stretchy.rb
CHANGED
@@ -10,13 +10,28 @@ require 'active_support/all'
|
|
10
10
|
require 'active_model/type/array'
|
11
11
|
require 'active_model/type/hash'
|
12
12
|
|
13
|
-
ActiveModel::Type.register(:array, ActiveModel::Type::Array)
|
14
|
-
ActiveModel::Type.register(:hash, ActiveModel::Type::Hash)
|
15
|
-
|
16
13
|
require_relative "stretchy/version"
|
17
14
|
require_relative "rails/instrumentation/railtie" if defined?(Rails)
|
18
15
|
|
16
|
+
|
17
|
+
|
19
18
|
module Stretchy
|
19
|
+
|
20
|
+
def self.loader
|
21
|
+
@loader ||= begin
|
22
|
+
loader = Zeitwerk::Loader.new
|
23
|
+
loader.tag = File.basename(__FILE__, ".rb")
|
24
|
+
loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
25
|
+
loader.push_dir(__dir__)
|
26
|
+
loader
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.boot!
|
31
|
+
loader.setup
|
32
|
+
Stretchy::Attributes.register!
|
33
|
+
end
|
34
|
+
|
20
35
|
module Errors
|
21
36
|
class QueryOptionMissing < StandardError; end
|
22
37
|
end
|
@@ -61,12 +76,9 @@ module Stretchy
|
|
61
76
|
end
|
62
77
|
end
|
63
78
|
|
64
|
-
end
|
65
79
|
|
80
|
+
end
|
66
81
|
|
82
|
+
Stretchy.loader.enable_reloading if defined?(Rails) && Rails.env.development? || ENV['RACK_ENV'] == 'development'
|
83
|
+
Stretchy.boot!
|
67
84
|
|
68
|
-
loader = Zeitwerk::Loader.new
|
69
|
-
loader.tag = File.basename(__FILE__, ".rb")
|
70
|
-
loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
|
71
|
-
loader.push_dir(__dir__)
|
72
|
-
loader.setup
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stretchy-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Spencer Markowski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: zeitwerk
|
@@ -178,6 +178,34 @@ dependencies:
|
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '3.0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: octokit
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '4.20'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - "~>"
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '4.20'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: versionomy
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: 0.5.0
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 0.5.0
|
181
209
|
description: Provides a familiar ActiveRecord-like interface for working with Elasticsearch
|
182
210
|
email:
|
183
211
|
- spencer.markowski@theablefew.com
|
@@ -204,6 +232,9 @@ files:
|
|
204
232
|
- lib/stretchy/associations.rb
|
205
233
|
- lib/stretchy/associations/associated_validator.rb
|
206
234
|
- lib/stretchy/associations/elastic_relation.rb
|
235
|
+
- lib/stretchy/attributes.rb
|
236
|
+
- lib/stretchy/attributes/transformers/keyword_transformer.rb
|
237
|
+
- lib/stretchy/attributes/type/keyword.rb
|
207
238
|
- lib/stretchy/common.rb
|
208
239
|
- lib/stretchy/delegation/delegate_cache.rb
|
209
240
|
- lib/stretchy/delegation/gateway_delegation.rb
|
@@ -217,6 +248,7 @@ files:
|
|
217
248
|
- lib/stretchy/record.rb
|
218
249
|
- lib/stretchy/refreshable.rb
|
219
250
|
- lib/stretchy/relation.rb
|
251
|
+
- lib/stretchy/relations/aggregation_methods.rb
|
220
252
|
- lib/stretchy/relations/finder_methods.rb
|
221
253
|
- lib/stretchy/relations/merger.rb
|
222
254
|
- lib/stretchy/relations/query_builder.rb
|
@@ -257,7 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
257
289
|
- !ruby/object:Gem::Version
|
258
290
|
version: '0'
|
259
291
|
requirements: []
|
260
|
-
rubygems_version: 3.3
|
292
|
+
rubygems_version: 3.5.3
|
261
293
|
signing_key:
|
262
294
|
specification_version: 4
|
263
295
|
summary: Rails ORM for Elasticsearch
|