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 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