stretchy-model 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a85f7bffcc11c54366d4cae7fec47b91341425e06b7f1c8a6269e0b23d4e649b
4
- data.tar.gz: cd0b9314fa734aa7af7179f12ed00626a17bc869186f82088158bfca87c8d915
3
+ metadata.gz: d7dff610329ad21128c58429c6f9d08b62138a7fad9adb0f610984bd744db1cf
4
+ data.tar.gz: 915256c1b413dd34d4777097b878f0c2c7886342b5d8dcfedc2159a405b3bdf2
5
5
  SHA512:
6
- metadata.gz: e193c837695100177eac9888841b14243596dfc9694515696ab1a9934174287c821cf52b2ca165e3f3eda04de9ba16c7c7330cb187641d71229d322c06674977
7
- data.tar.gz: 21ace7b64f85d505a05b61b89b5b85d9d2af34941b57672da45f70e6c8736e8b9451c59891fef7d0795f8b54076cffd88bfc141fcd4da1c1f8ffaddcf8276697
6
+ metadata.gz: 66f98b878a8e78d9d79b53f05edf89a8d4a61d4fd3a5b98d93ef349491c7c87f36d4cadb857b8be5e9e992308609c22d1abc45703eb39b95e78240d87c6ae081
7
+ data.tar.gz: 0eabc3b84d0aecb0f8051bf53238ec6da5d431c7ff5d0f7c3be20888a20252504e3324c7b558fe455d90c2cf0db827b1d0440e6d03d211569ed8ed7d60dade01
data/README.md CHANGED
@@ -98,16 +98,6 @@ Model.bulk_in_batches(records, size: 100) do |batch|
98
98
  end
99
99
  ```
100
100
 
101
-
102
- ## Instrumentation
103
- ```ruby
104
- Blanket.first
105
- ```
106
-
107
- ```sh
108
- Blanket (6.322ms) curl -X GET 'http://localhost:9200/blankets/_search?size=1' -d '{"sort":{"date":"desc"}}'
109
- ```
110
-
111
101
  ## Installation
112
102
 
113
103
  Install the gem and add to the application's Gemfile by executing:
@@ -131,6 +121,12 @@ rails credentials:edit
131
121
  ```yaml
132
122
  elasticsearch:
133
123
  url: localhost:9200
124
+
125
+ # or opensearch
126
+ # opensearch:
127
+ # host: https://localhost:9200
128
+ # user: admin
129
+ # password: admin
134
130
  ```
135
131
 
136
132
  #### Create an initializer
@@ -154,6 +150,21 @@ After checking out the repo, run `bin/setup` to install dependencies. You can al
154
150
  > Full documentation on [Elasticsearch Query DSL and Aggregation options](https://github.com/elastic/elasticsearch-rails/tree/main/elasticsearch-persistence)
155
151
 
156
152
  ## Testing
153
+ <details>
154
+ <summary>Act</summary>
155
+
156
+ Run github action workflow locally
157
+
158
+ ```sh
159
+ brew install act --HEAD
160
+ ```
161
+
162
+ ```sh
163
+ act -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:runner-latest
164
+ ```
165
+
166
+ </details>
167
+
157
168
  <details>
158
169
  <summary>Elasticsearch</summary>
159
170
 
data/Rakefile CHANGED
@@ -2,3 +2,95 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  task default: %i[]
5
+
6
+ require 'octokit'
7
+ require 'versionomy'
8
+ require 'rainbow'
9
+
10
+ def determine_current_version
11
+ # Load current version
12
+ load 'lib/stretchy/version.rb'
13
+ current_version = Versionomy.parse(Stretchy::VERSION)
14
+ end
15
+
16
+ def determine_new_version(version)
17
+ # Load current version
18
+ current_version = determine_current_version
19
+
20
+ # Determine new version
21
+ case version.to_sym
22
+ when :major
23
+ current_version.bump(:major)
24
+ when :minor
25
+ current_version.bump(:minor)
26
+ when :patch
27
+ current_version.bump(:tiny)
28
+ else
29
+ version =~ /\Av?\d+\.\d+\.\d+\z/ ? Versionomy.parse(version).to_s.gsub(/v/,'') : current_version
30
+ end
31
+ end
32
+
33
+ def create_release_branch(new_version, base_branch)
34
+ system("git stash save 'Changes before creating release branch'")
35
+ system("git fetch origin #{base_branch}")
36
+ branch_name = "release/v#{new_version}"
37
+ system("git checkout -b #{branch_name} #{base_branch}")
38
+ branch_name
39
+ end
40
+
41
+ def update_version_file(new_version)
42
+ # Update lib/stretchy/version.rb
43
+ File.open('lib/stretchy/version.rb', 'w') do |file|
44
+ file.puts "module Stretchy\n VERSION = '#{new_version}'\nend"
45
+ end
46
+ end
47
+
48
+ def commit_and_push_changes(new_version, branch_name)
49
+ system("git add lib/stretchy/version.rb")
50
+ system("git commit -m 'Bump version to v#{new_version}'")
51
+ system("git tag v#{new_version}")
52
+ system("git push origin #{branch_name} --tags -f")
53
+ end
54
+
55
+ def create_pull_request(new_version, base_branch, branch_name)
56
+ # Create a pull request
57
+ client = Octokit::Client.new(access_token: ENV['GH_TOKEN'])
58
+ client.create_pull_request('theablefew/stretchy', base_branch, branch_name, "Release v#{new_version}")
59
+ end
60
+
61
+ namespace :publish do
62
+ desc "Create a release"
63
+ task :release, [:version, :base_branch] do |t, args|
64
+ args.with_defaults(version: :patch, base_branch: 'main')
65
+ version = args[:version]
66
+ base_branch = args[:base_branch]
67
+
68
+ old_version = determine_current_version
69
+ new_version = determine_new_version(version)
70
+ puts Rainbow("Bumping version from #{old_version} to #{new_version}").green
71
+ branch_name = create_release_branch(new_version, base_branch)
72
+ begin
73
+ update_version_file(new_version)
74
+ commit_and_push_changes(new_version, branch_name)
75
+ create_pull_request(new_version, base_branch, branch_name)
76
+ rescue => e
77
+ puts "Error: #{e.message}"
78
+ puts "Rolling back changes"
79
+ system("git tag -d v#{new_version}")
80
+ system("git checkout #{base_branch}")
81
+ system("git branch -D #{branch_name}")
82
+ end
83
+ end
84
+
85
+ task :major do
86
+ Rake::Task['publish:release'].invoke('major')
87
+ end
88
+
89
+ task :minor do
90
+ Rake::Task['publish:release'].invoke('minor')
91
+ end
92
+
93
+ task :patch do
94
+ Rake::Task['publish:release'].invoke('patch')
95
+ end
96
+ end
@@ -0,0 +1,85 @@
1
+ module Stretchy
2
+ module Attributes
3
+ module Transformers
4
+ class KeywordTransformer
5
+
6
+ KEYWORD_AGGREGATION_KEYS = [:terms, :rare_terms, :significant_terms, :cardinality, :string_stats]
7
+
8
+ attr_reader :attribute_types
9
+
10
+ def initialize(attribute_types)
11
+ @attribute_types = attribute_types
12
+ end
13
+
14
+ def cast_value_keys
15
+ values.transform_values do |value|
16
+ case value
17
+ when Array
18
+ value.map { |item| transform_keys_for_item(item) }
19
+ when Hash
20
+ transform_keys_for_item(value)
21
+ else
22
+ value
23
+ end
24
+ end
25
+ end
26
+
27
+ def keyword?(arg)
28
+ attr = @attribute_types[arg.to_s]
29
+ return false unless attr
30
+ attr.is_a?(Stretchy::Attributes::Type::Keyword)
31
+ end
32
+
33
+ def protected?(arg)
34
+ return false if arg.nil?
35
+ Stretchy::Relations::AggregationMethods::AGGREGATION_METHODS.include?(arg.to_sym)
36
+ end
37
+
38
+ def transform(item, *ignore)
39
+ item.each_with_object({}) do |(k, v), new_item|
40
+ if ignore && ignore.include?(k)
41
+ new_item[k] = v
42
+ next
43
+ end
44
+ new_key = (!protected?(k) && keyword?(k)) ? "#{k}.keyword" : k
45
+
46
+ new_value = v
47
+
48
+ if new_value.is_a?(Hash)
49
+ new_value = transform(new_value)
50
+ elsif new_value.is_a?(Array)
51
+ new_value = new_value.map { |i| i.is_a?(Hash) ? transform(i) : i }
52
+ elsif new_value.is_a?(String) || new_value.is_a?(Symbol)
53
+ new_value = "#{new_value}.keyword" if keyword?(new_value)
54
+ end
55
+
56
+ new_item[new_key] = new_value
57
+ end
58
+ end
59
+
60
+ # If terms are used, we assume that the field is a keyword field
61
+ # and append .keyword to the field name
62
+ # {terms: {field: 'gender'}}
63
+ # or nested aggs
64
+ # {terms: {field: 'gender'}, aggs: {name: {terms: {field: 'position.name'}}}}
65
+ # should be converted to
66
+ # {terms: {field: 'gender.keyword'}, aggs: {name: {terms: {field: 'position.name.keyword'}}}}
67
+ # {date_histogram: {field: 'created_at', interval: 'day'}}
68
+ # TODO: There may be cases where we don't want to add .keyword to the field and there should be a way to override this
69
+ def assume_keyword_field(args={}, parent_match=false)
70
+ if args.is_a?(Hash)
71
+ args.each do |k, v|
72
+ if v.is_a?(Hash)
73
+ assume_keyword_field(v, KEYWORD_AGGREGATION_FIELDS.include?(k))
74
+ else
75
+ next unless v.is_a?(String) || v.is_a?(Symbol)
76
+ args[k] = ([:field, :fields].include?(k.to_sym) && v !~ /\.keyword$/ && parent_match) ? "#{v}.keyword" : v.to_s
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,11 @@
1
+ module Stretchy
2
+ module Attributes
3
+ module Type
4
+ class Keyword < ActiveModel::Type::String # :nodoc:
5
+ def type
6
+ :keyword
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module Stretchy
2
+ module Attributes
3
+
4
+ def self.register!
5
+ ActiveModel::Type.register(:array, ActiveModel::Type::Array)
6
+ ActiveModel::Type.register(:hash, ActiveModel::Type::Hash)
7
+ ActiveModel::Type.register(:keyword, Stretchy::Attributes::Type::Keyword)
8
+ end
9
+ end
10
+ end
@@ -1,11 +1,12 @@
1
1
  module Stretchy
2
2
  module Querying
3
3
  delegate :first, :first!, :last, :last!, :exists?, :has_field, :any?, :many?, to: :all
4
- delegate :order, :limit, :size, :sort, :where, :rewhere, :eager_load, :includes, :create_with, :none, :unscope, to: :all
5
- delegate :or_filter, :filter, :fields, :source, :highlight, :aggregation, to: :all
6
- delegate :skip_callbacks, :routing, to: :all
7
- delegate :search_options, :routing, to: :all
8
- delegate :must, :must_not, :should, :where_not, :query_string, to: :all
4
+ delegate :order, :limit, :size, :sort, :rewhere, :eager_load, :includes, :create_with, :none, :unscope, to: :all
5
+ delegate :or_filter, :fields, :source, :highlight, to: :all
6
+ delegate *Stretchy::Relations::AggregationMethods::AGGREGATION_METHODS, to: :all
7
+
8
+ delegate :skip_callbacks, :routing, :search_options, to: :all
9
+ delegate :must, :must_not, :should, :where_not, :where, :filter_query, :query_string, to: :all
9
10
 
10
11
  def fetch_results(es)
11
12
  unless es.count?
@@ -4,7 +4,7 @@ module Stretchy
4
4
  class Relation
5
5
 
6
6
  # These methods can accept multiple values.
7
- MULTI_VALUE_METHODS = [:order, :where, :or_filter, :filter, :bind, :extending, :unscope, :skip_callbacks]
7
+ MULTI_VALUE_METHODS = [:order, :where, :or_filter, :filter_query, :bind, :extending, :unscope, :skip_callbacks]
8
8
 
9
9
  # These methods can accept a single value.
10
10
  SINGLE_VALUE_METHODS = [:limit, :offset, :routing, :size]
@@ -16,7 +16,7 @@ module Stretchy
16
16
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
17
17
 
18
18
  # Include modules.
19
- include Relations::FinderMethods, Relations::SpawnMethods, Relations::QueryMethods, Relations::SearchOptionMethods, Delegation
19
+ include Relations::FinderMethods, Relations::SpawnMethods, Relations::QueryMethods, Relations::AggregationMethods, Relations::SearchOptionMethods, Delegation
20
20
 
21
21
  # Getters.
22
22
  attr_reader :klass, :loaded
@@ -162,7 +162,7 @@ module Stretchy
162
162
  #
163
163
  # @return [QueryBuilder] The query builder for the relation.
164
164
  def query_builder
165
- Relations::QueryBuilder.new(values)
165
+ Relations::QueryBuilder.new(values, klass.attribute_types)
166
166
  end
167
167
 
168
168
  end