switch_searchable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5ba9fd6bd972bc10b563a5db10db7197b7f9ab3d
4
+ data.tar.gz: 735f1ca6f3d49405615b3125a9f6c46b3549f7a6
5
+ SHA512:
6
+ metadata.gz: 077a86694dcb3ca68de0fe1e28597a10164d1286dd772035365a1faa787a0a0d052676ea7a7f9f7710e4ecfc8731e1106710cf18c3c48c4b141d0a1a333ac428
7
+ data.tar.gz: 9481c68b69d7e8853164f6568dbf9de2f709a7bd84e218c2ff4f09e60086a6bc75aad924cd777e6a4c5665592f2a0ec497de40059c48c54b5455aa9f164f3770
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.4
5
+ before_install: gem install bundler -v 1.15.3
File without changes
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in switch_searchable.gemspec
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,56 @@
1
+ # SwitchSearchable
2
+
3
+ Manages multiple search engines in your Rails app. Supported are - PGSearch, AlgoliaSearch and Elasticsearch.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'switch_searchable'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install switch_searchable
20
+
21
+ ## Usage
22
+
23
+ ***Make sure you have setup services with Algolia, Elasticsearch. If you are using Postgresql nothing needs to be setup.***
24
+
25
+ In your AR model:
26
+
27
+ ```ruby
28
+ class Lead < ActiveRecord::Base
29
+ include SwitchSearchable::Searchable
30
+
31
+ searchable_attributes(
32
+ :company_name,
33
+ :first_name,
34
+ :last_name,
35
+ :email,
36
+ {phones: [:number]}
37
+ )
38
+
39
+ has_may :phones
40
+ end
41
+ ```
42
+
43
+ To create an index, run:
44
+
45
+ ```
46
+ Lead.reindex!
47
+ ```
48
+
49
+ After that, you can now search:
50
+ ```
51
+ Lead.search("Neil the man")
52
+ ```
53
+
54
+ ## License
55
+
56
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "switch_searchable"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,11 @@
1
+ require "pg_search"
2
+ require "algoliasearch-rails"
3
+ require "elasticsearch/rails"
4
+ require "elasticsearch/model"
5
+ require "switch_searchable/version"
6
+ require "switch_searchable/searchable"
7
+ require "switch_searchable/search_engine/algolia"
8
+ require "switch_searchable/search_engine/elasticsearch"
9
+ require "switch_searchable/search_engine/postgres"
10
+
11
+ module SwitchSearchable; end
@@ -0,0 +1,109 @@
1
+ module SwitchSearchable
2
+ module SearchEngine
3
+ module Algolia
4
+ class BadConfiguration < StandardError; end
5
+ class RequiredMethodNotDefined < StandardError; end
6
+
7
+ class << self
8
+ def included(klass)
9
+ raise_errors
10
+
11
+ klass.class_eval do
12
+ extend ClassMethods
13
+ include AlgoliaSearch
14
+ end
15
+ end
16
+
17
+ def raise_errors
18
+ raise(
19
+ BadConfiguration,
20
+ "Please add ALGOLIA_APP_ID in your environment variables"
21
+ ) unless ENV["ALGOLIA_APP_ID"]
22
+
23
+ raise(
24
+ BadConfiguration,
25
+ "Please add ALGOLIA_API_KEY in your environment variables"
26
+ ) unless ENV["ALGOLIA_APP_ID"]
27
+
28
+ raise(
29
+ BadConfiguration,
30
+ "Please add ALGOLIA_ENVIRONMENT in your environment variables"
31
+ ) unless ENV["ALGOLIA_ENVIRONMENT"]
32
+ end
33
+
34
+ module ClassMethods
35
+ def init_search_engine(*names)
36
+ algoliasearch index_name: "#{self.to_s}_#{ENV["ALGOLIA_ENVIRONMENT"]}" do
37
+ names.flatten.each do |name|
38
+ if name.is_a? Symbol
39
+ attribute(name)
40
+ elsif name.is_a? Hash
41
+ name.keys.each do |key|
42
+ array = name[key]
43
+ raise(
44
+ BadDataType,
45
+ "searchable_attributes associations can only have Array"
46
+ ) unless array.is_a? Array
47
+
48
+ attribute(key) do
49
+ value = send(key)
50
+ unless value.blank?
51
+ if value.respond_to? :to_a
52
+ value.map do |v|
53
+ array.inject({}) do |hash, element|
54
+ raise(
55
+ BadDataType,
56
+ "searchable_attributes associations
57
+ attributes can only have Symbol"
58
+ ) unless array.is_a? Array
59
+
60
+ hash[element] = v.send(element)
61
+ end
62
+ end
63
+ else
64
+ array.inject({}) do |hash, element|
65
+ raise(
66
+ BadDataType,
67
+ "searchable_attributes associations
68
+ attributes can only have Symbol"
69
+ ) unless array.is_a? Array
70
+
71
+ hash[element] = value.send(element)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ else
78
+ raise(
79
+ BadDataType,
80
+ "searchable_attributes can only be
81
+ either a Symbol or an Array"
82
+ )
83
+ end
84
+ end
85
+
86
+ searchable_attrs = names.flatten.map do |name|
87
+ if name.is_a? Hash
88
+ name.keys
89
+ else
90
+ name
91
+ end
92
+ end.flatten
93
+
94
+ searchableAttributes(searchable_attrs)
95
+ end
96
+ end
97
+
98
+ def search(term)
99
+ algolia_search(term)
100
+ end
101
+
102
+ def reindex_search_engine!
103
+ algolia_reindex!
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,111 @@
1
+ module SwitchSearchable
2
+ module SearchEngine
3
+ module Elasticsearch
4
+ class BadConfiguration < StandardError; end
5
+ class BadDataType < StandardError; end
6
+
7
+ class << self
8
+ def included(klass)
9
+ raise_errors
10
+
11
+ klass.class_eval do
12
+ extend ClassMethods
13
+ include ::Elasticsearch::Model
14
+ include ::Elasticsearch::Model::Callbacks
15
+ end
16
+ end
17
+
18
+ def raise_errors
19
+ raise(
20
+ BadConfiguration,
21
+ "Please add ELASTICSEARCH_HOST in your environment variables"
22
+ ) unless ENV["ELASTICSEARCH_HOST"]
23
+ end
24
+
25
+ module ClassMethods
26
+ def init_search_engine(*names)
27
+ index_name Rails.application.class.parent_name.underscore
28
+ document_type self.name.downcase
29
+
30
+ fields = names.flatten.inject([]) do |result_arr, name|
31
+ if name.is_a? Symbol
32
+ result_arr << name
33
+ elsif name.is_a? Hash
34
+ name.keys.each do |key|
35
+ array = name[key]
36
+ raise(
37
+ BadDataType,
38
+ "searchable_attributes associations can only have Array"
39
+ ) unless array.is_a? Array
40
+
41
+ result = array.inject([]) do |array, element|
42
+ raise(
43
+ BadDataType,
44
+ "searchable_attributes associations
45
+ attributes can only have Symbol"
46
+ ) unless array.is_a? Array
47
+
48
+ array << key.to_s + "." + element.to_s
49
+ end
50
+
51
+ result_arr << result
52
+ end
53
+ else
54
+ raise(
55
+ BadDataType,
56
+ "searchable_attributes can only be either a Symbol or an Hash"
57
+ )
58
+ end
59
+
60
+ result_arr.flatten
61
+ end
62
+
63
+ define_singleton_method(:call_search) do |term|
64
+ __elasticsearch__.search(
65
+ { query:
66
+ { multi_match:
67
+ { query: term, fields: fields}
68
+ },
69
+ size: 10000,
70
+ }
71
+ )
72
+ end
73
+
74
+ as_indexed_hash = names.flatten.inject({}) do |result_hash, name|
75
+ if name.is_a? Hash
76
+ name.keys.each do |key|
77
+ array = name[key]
78
+ raise(
79
+ BadDataType,
80
+ "searchable_attributes associations can only have Array"
81
+ ) unless array.is_a? Array
82
+
83
+ result_hash[key] = { only: array }
84
+ end
85
+ end
86
+
87
+ result_hash
88
+ end
89
+
90
+ define_method(:as_indexed_json) do |options|
91
+ self.as_json(only: names.flatten, include: as_indexed_hash)
92
+ end
93
+ end
94
+
95
+ def search(term)
96
+ connection
97
+ call_search(term).records
98
+ end
99
+
100
+ def reindex_search_engine!
101
+ puts "Creating index..."
102
+ __elasticsearch__.create_index! force: true
103
+ __elasticsearch__.refresh_index!
104
+ puts "Importing data..."
105
+ import
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,51 @@
1
+ module SwitchSearchable
2
+ module SearchEngine
3
+ module Postgres
4
+ class BadConfiguration < StandardError; end
5
+
6
+ class << self
7
+ def included(klass)
8
+ raise_errors
9
+
10
+ klass.class_eval do
11
+ extend ClassMethods
12
+ include PgSearch
13
+ end
14
+ end
15
+
16
+ def raise_errors; end
17
+
18
+ module ClassMethods
19
+ def init_search_engine(*names)
20
+ trigram_threshold = {using: {trigram: {
21
+ threshold: 0.05
22
+ }}}
23
+
24
+ # there should only be one Hash in *names
25
+ associated_against = nil
26
+ against = names.flatten.inject([]) do |array, value|
27
+ if value.is_a? Symbol
28
+ array << value
29
+ elsif value.is_a? Hash
30
+ associated_against = value
31
+ end
32
+
33
+ array
34
+ end
35
+
36
+ pg_search_scope(:pg_search, {
37
+ against: against,
38
+ associated_against: associated_against,
39
+ }.merge(trigram_threshold))
40
+ end
41
+
42
+ def search(term)
43
+ pg_search(term)
44
+ end
45
+
46
+ def reindex_search_engine!; end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,65 @@
1
+ module SwitchSearchable
2
+ module Searchable
3
+ class BadConfiguration < StandardError; end
4
+ class RequiredMethodNotDefined < StandardError; end
5
+
6
+ class << self
7
+ def included(klass)
8
+ check_config
9
+
10
+ klass.class_eval do
11
+ extend ClassMethods
12
+ include "SwitchSearchable::SearchEngine::#{ENV["SEARCH_ENGINE"]}".
13
+ constantize
14
+ end
15
+
16
+ check_methods(klass)
17
+ end
18
+
19
+ def check_config
20
+ raise(
21
+ BadConfiguration,
22
+ "Please add SEARCH_ENGINE in your environment variables"
23
+ ) unless ENV["SEARCH_ENGINE"]
24
+ end
25
+
26
+ def check_methods(klass)
27
+ raise(
28
+ RequiredMethodNotDefined,
29
+ ":raise_errors method not defined in your search engine"
30
+ ) unless "SwitchSearchable::SearchEngine::#{ENV["SEARCH_ENGINE"]}".
31
+ constantize.respond_to? :raise_errors
32
+
33
+ raise(
34
+ RequiredMethodNotDefined,
35
+ ":search method not defined in your search engine"
36
+ ) unless klass.respond_to? :search
37
+
38
+ raise(
39
+ RequiredMethodNotDefined,
40
+ ":reindex_search_engine! method not defined in your search engine"
41
+ ) unless klass.respond_to? :reindex_search_engine!
42
+
43
+ raise(
44
+ RequiredMethodNotDefined,
45
+ ":init_search_engine method not defined in your search engine"
46
+ ) unless klass.respond_to? :init_search_engine
47
+ end
48
+
49
+ module ClassMethods
50
+ def searchable_attributes(*names)
51
+ init_search_engine(names)
52
+ end
53
+
54
+ def search(term)
55
+ "SwitchSearchable::SearchEngine::#{ENV["SEARCH_ENGINE"]}".
56
+ constantize.search(term)
57
+ end
58
+
59
+ def reindex!
60
+ reindex_search_engine!
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module SwitchSearchable
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "switch_searchable/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "switch_searchable"
8
+ spec.version = SwitchSearchable::VERSION
9
+ spec.authors = ["Neil Marion dela Cruz"]
10
+ spec.email = ["nmfdelacruz@gmail.com"]
11
+
12
+ spec.summary = %q{Manages different search engines in a Rails app}
13
+ spec.description = %q{Manages different search engines in a Rails app}
14
+ spec.homepage = "https://github.com/carabao-capital/switch_searchable"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_runtime_dependency "pg_search", "~> 2.1.0", ">= 2.1.0"
25
+ spec.add_runtime_dependency "algoliasearch-rails", "~> 1.20.1", ">= 1.20.1"
26
+ spec.add_runtime_dependency "elasticsearch-model", "~> 5.0.1", ">= 5.0.1"
27
+ spec.add_runtime_dependency "elasticsearch-rails", "~> 5.0.1", ">= 5.0.1"
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.15"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec", "~> 3.0"
32
+ end
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: switch_searchable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Neil Marion dela Cruz
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-08-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pg_search
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.1.0
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 2.1.0
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.1.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: algoliasearch-rails
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 1.20.1
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.20.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 1.20.1
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.20.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: elasticsearch-model
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 5.0.1
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 5.0.1
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 5.0.1
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 5.0.1
73
+ - !ruby/object:Gem::Dependency
74
+ name: elasticsearch-rails
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: 5.0.1
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 5.0.1
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 5.0.1
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 5.0.1
93
+ - !ruby/object:Gem::Dependency
94
+ name: bundler
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.15'
100
+ type: :development
101
+ prerelease: false
102
+ version_requirements: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '1.15'
107
+ - !ruby/object:Gem::Dependency
108
+ name: rake
109
+ requirement: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '10.0'
114
+ type: :development
115
+ prerelease: false
116
+ version_requirements: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '10.0'
121
+ - !ruby/object:Gem::Dependency
122
+ name: rspec
123
+ requirement: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '3.0'
128
+ type: :development
129
+ prerelease: false
130
+ version_requirements: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '3.0'
135
+ description: Manages different search engines in a Rails app
136
+ email:
137
+ - nmfdelacruz@gmail.com
138
+ executables: []
139
+ extensions: []
140
+ extra_rdoc_files: []
141
+ files:
142
+ - ".gitignore"
143
+ - ".rspec"
144
+ - ".travis.yml"
145
+ - CHANGELOG.md
146
+ - Gemfile
147
+ - LICENSE.txt
148
+ - README.md
149
+ - Rakefile
150
+ - bin/console
151
+ - bin/setup
152
+ - lib/switch_searchable.rb
153
+ - lib/switch_searchable/search_engine/algolia.rb
154
+ - lib/switch_searchable/search_engine/elasticsearch.rb
155
+ - lib/switch_searchable/search_engine/postgres.rb
156
+ - lib/switch_searchable/searchable.rb
157
+ - lib/switch_searchable/version.rb
158
+ - switch_searchable.gemspec
159
+ homepage: https://github.com/carabao-capital/switch_searchable
160
+ licenses:
161
+ - MIT
162
+ metadata: {}
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubyforge_project:
179
+ rubygems_version: 2.6.11
180
+ signing_key:
181
+ specification_version: 4
182
+ summary: Manages different search engines in a Rails app
183
+ test_files: []