seek_party 0.0.1
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 +7 -0
- data/.gitignore +14 -0
- data/.rakeTasks +7 -0
- data/.rspec +3 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +167 -0
- data/LICENSE.txt +21 -0
- data/README.md +164 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/seek_party/seek_party_attribute.rb +47 -0
- data/lib/seek_party/seek_party_engine.rb +41 -0
- data/lib/seek_party/seek_party_query.rb +86 -0
- data/lib/seek_party/version.rb +3 -0
- data/lib/seek_party.rb +27 -0
- data/seek_party.gemspec +34 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7366a41454326575b488a8149cefab4ee1fa184b9df1695e332cf3b114cae5cc
|
4
|
+
data.tar.gz: ebc591f2d3f4a962f953df3caf19f986560f2838fb9b5688f3b71bb70e38f779
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5c360583067ade61cbb950fe07eca9f00b03cafa1843f61d880bf1bf32cb61938a05becf230efe5cd86b6290a57bb506a705861cfb61d4bd6fabd6eecf437601
|
7
|
+
data.tar.gz: b04839f0ba524ae18fd0f62406a9b6252f33c5e2ad95407b2a25e2802810af66aedc309acdd44b7bd2add6e7015f7f9ed5a2cf49e0bed59b788914cfdae7ca9f
|
data/.gitignore
ADDED
data/.rakeTasks
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<Settings><!--This file was automatically generated by Ruby plugin.
|
3
|
+
You are allowed to:
|
4
|
+
1. Remove rake task
|
5
|
+
2. Add existing rake tasks
|
6
|
+
To add existing rake tasks automatically delete this file and reload the project.
|
7
|
+
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build seek_party-0.0.1.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated files" fullCmd="clobber" taksId="clobber" /><RakeTask description="Build and install seek_party-0.0.1.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install seek_party-0.0.1.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.0.1 and build and push seek_party-0.0.1.gem to rubygems.org" fullCmd="release[remote]" taksId="release[remote]" /><RakeTask description="Run RSpec code examples" fullCmd="spec" taksId="spec" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
|
data/.rspec
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at charles_was_7@hotmail.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
ruby '2.6.3'
|
4
|
+
|
5
|
+
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
6
|
+
gem 'rails', '~> 5.2.3'
|
7
|
+
|
8
|
+
group :test do
|
9
|
+
# Use sqlite3 as the database for Active Record
|
10
|
+
gem 'sqlite3'
|
11
|
+
|
12
|
+
# Use rspec as the test tool
|
13
|
+
gem 'rspec-rails', '~> 3.6'
|
14
|
+
|
15
|
+
# Use codeclimate-test-reporter to report tests to codeclimate
|
16
|
+
gem 'codeclimate-test-reporter'
|
17
|
+
|
18
|
+
# Use simplecov to generate the coverage results
|
19
|
+
gem 'simplecov', require: false
|
20
|
+
end
|
21
|
+
|
22
|
+
# Specify your gem's dependencies in seek_party.gemspec
|
23
|
+
gemspec
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
seek_party (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
actioncable (5.2.4)
|
10
|
+
actionpack (= 5.2.4)
|
11
|
+
nio4r (~> 2.0)
|
12
|
+
websocket-driver (>= 0.6.1)
|
13
|
+
actionmailer (5.2.4)
|
14
|
+
actionpack (= 5.2.4)
|
15
|
+
actionview (= 5.2.4)
|
16
|
+
activejob (= 5.2.4)
|
17
|
+
mail (~> 2.5, >= 2.5.4)
|
18
|
+
rails-dom-testing (~> 2.0)
|
19
|
+
actionpack (5.2.4)
|
20
|
+
actionview (= 5.2.4)
|
21
|
+
activesupport (= 5.2.4)
|
22
|
+
rack (~> 2.0)
|
23
|
+
rack-test (>= 0.6.3)
|
24
|
+
rails-dom-testing (~> 2.0)
|
25
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
26
|
+
actionview (5.2.4)
|
27
|
+
activesupport (= 5.2.4)
|
28
|
+
builder (~> 3.1)
|
29
|
+
erubi (~> 1.4)
|
30
|
+
rails-dom-testing (~> 2.0)
|
31
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
32
|
+
activejob (5.2.4)
|
33
|
+
activesupport (= 5.2.4)
|
34
|
+
globalid (>= 0.3.6)
|
35
|
+
activemodel (5.2.4)
|
36
|
+
activesupport (= 5.2.4)
|
37
|
+
activerecord (5.2.4)
|
38
|
+
activemodel (= 5.2.4)
|
39
|
+
activesupport (= 5.2.4)
|
40
|
+
arel (>= 9.0)
|
41
|
+
activestorage (5.2.4)
|
42
|
+
actionpack (= 5.2.4)
|
43
|
+
activerecord (= 5.2.4)
|
44
|
+
marcel (~> 0.3.1)
|
45
|
+
activesupport (5.2.4)
|
46
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
47
|
+
i18n (>= 0.7, < 2)
|
48
|
+
minitest (~> 5.1)
|
49
|
+
tzinfo (~> 1.1)
|
50
|
+
arel (9.0.0)
|
51
|
+
builder (3.2.3)
|
52
|
+
codeclimate-test-reporter (1.0.7)
|
53
|
+
simplecov
|
54
|
+
concurrent-ruby (1.1.5)
|
55
|
+
crass (1.0.5)
|
56
|
+
diff-lcs (1.3)
|
57
|
+
docile (1.3.2)
|
58
|
+
erubi (1.9.0)
|
59
|
+
globalid (0.4.2)
|
60
|
+
activesupport (>= 4.2.0)
|
61
|
+
i18n (1.7.0)
|
62
|
+
concurrent-ruby (~> 1.0)
|
63
|
+
json (2.2.0)
|
64
|
+
loofah (2.4.0)
|
65
|
+
crass (~> 1.0.2)
|
66
|
+
nokogiri (>= 1.5.9)
|
67
|
+
mail (2.7.1)
|
68
|
+
mini_mime (>= 0.1.1)
|
69
|
+
marcel (0.3.3)
|
70
|
+
mimemagic (~> 0.3.2)
|
71
|
+
method_source (0.9.2)
|
72
|
+
mimemagic (0.3.3)
|
73
|
+
mini_mime (1.0.2)
|
74
|
+
mini_portile2 (2.4.0)
|
75
|
+
minitest (5.13.0)
|
76
|
+
nio4r (2.5.2)
|
77
|
+
nokogiri (1.10.7)
|
78
|
+
mini_portile2 (~> 2.4.0)
|
79
|
+
rack (2.0.7)
|
80
|
+
rack-test (1.1.0)
|
81
|
+
rack (>= 1.0, < 3)
|
82
|
+
rails (5.2.4)
|
83
|
+
actioncable (= 5.2.4)
|
84
|
+
actionmailer (= 5.2.4)
|
85
|
+
actionpack (= 5.2.4)
|
86
|
+
actionview (= 5.2.4)
|
87
|
+
activejob (= 5.2.4)
|
88
|
+
activemodel (= 5.2.4)
|
89
|
+
activerecord (= 5.2.4)
|
90
|
+
activestorage (= 5.2.4)
|
91
|
+
activesupport (= 5.2.4)
|
92
|
+
bundler (>= 1.3.0)
|
93
|
+
railties (= 5.2.4)
|
94
|
+
sprockets-rails (>= 2.0.0)
|
95
|
+
rails-dom-testing (2.0.3)
|
96
|
+
activesupport (>= 4.2.0)
|
97
|
+
nokogiri (>= 1.6)
|
98
|
+
rails-html-sanitizer (1.3.0)
|
99
|
+
loofah (~> 2.3)
|
100
|
+
railties (5.2.4)
|
101
|
+
actionpack (= 5.2.4)
|
102
|
+
activesupport (= 5.2.4)
|
103
|
+
method_source
|
104
|
+
rake (>= 0.8.7)
|
105
|
+
thor (>= 0.19.0, < 2.0)
|
106
|
+
rake (10.5.0)
|
107
|
+
rspec (3.8.0)
|
108
|
+
rspec-core (~> 3.8.0)
|
109
|
+
rspec-expectations (~> 3.8.0)
|
110
|
+
rspec-mocks (~> 3.8.0)
|
111
|
+
rspec-core (3.8.2)
|
112
|
+
rspec-support (~> 3.8.0)
|
113
|
+
rspec-expectations (3.8.4)
|
114
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
115
|
+
rspec-support (~> 3.8.0)
|
116
|
+
rspec-mocks (3.8.1)
|
117
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
118
|
+
rspec-support (~> 3.8.0)
|
119
|
+
rspec-rails (3.8.2)
|
120
|
+
actionpack (>= 3.0)
|
121
|
+
activesupport (>= 3.0)
|
122
|
+
railties (>= 3.0)
|
123
|
+
rspec-core (~> 3.8.0)
|
124
|
+
rspec-expectations (~> 3.8.0)
|
125
|
+
rspec-mocks (~> 3.8.0)
|
126
|
+
rspec-support (~> 3.8.0)
|
127
|
+
rspec-support (3.8.2)
|
128
|
+
simplecov (0.17.1)
|
129
|
+
docile (~> 1.1)
|
130
|
+
json (>= 1.8, < 3)
|
131
|
+
simplecov-html (~> 0.10.0)
|
132
|
+
simplecov-html (0.10.2)
|
133
|
+
sprockets (4.0.0)
|
134
|
+
concurrent-ruby (~> 1.0)
|
135
|
+
rack (> 1, < 3)
|
136
|
+
sprockets-rails (3.2.1)
|
137
|
+
actionpack (>= 4.0)
|
138
|
+
activesupport (>= 4.0)
|
139
|
+
sprockets (>= 3.0.0)
|
140
|
+
sqlite3 (1.4.1)
|
141
|
+
thor (0.20.3)
|
142
|
+
thread_safe (0.3.6)
|
143
|
+
tzinfo (1.2.5)
|
144
|
+
thread_safe (~> 0.1)
|
145
|
+
websocket-driver (0.7.1)
|
146
|
+
websocket-extensions (>= 0.1.0)
|
147
|
+
websocket-extensions (0.1.4)
|
148
|
+
|
149
|
+
PLATFORMS
|
150
|
+
ruby
|
151
|
+
|
152
|
+
DEPENDENCIES
|
153
|
+
bundler (~> 2.0)
|
154
|
+
codeclimate-test-reporter
|
155
|
+
rails (~> 5.2.3)
|
156
|
+
rake (~> 10.0)
|
157
|
+
rspec (~> 3.0)
|
158
|
+
rspec-rails (~> 3.6)
|
159
|
+
seek_party!
|
160
|
+
simplecov
|
161
|
+
sqlite3
|
162
|
+
|
163
|
+
RUBY VERSION
|
164
|
+
ruby 2.6.3p62
|
165
|
+
|
166
|
+
BUNDLED WITH
|
167
|
+
2.0.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 Charles Washington
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# SeekParty - Searches made easy
|
2
|
+
|
3
|
+
<p align="center">
|
4
|
+
<img width="1000" height="204" src="https://i.ibb.co/CHjZYwj/search-party-logo-vector.png">
|
5
|
+
</p>
|
6
|
+
|
7
|
+
### What is this?
|
8
|
+
|
9
|
+
Have you ever had to write a search functionality for a web application and found yourself
|
10
|
+
having to write SQL code?
|
11
|
+
|
12
|
+
**Then this is for you.**
|
13
|
+
|
14
|
+
SeekParty adds the method #search to classes that extend it. Once called, SeekParty builds and runs those ugly SQL
|
15
|
+
queries in a nice way by inspecting your attributes and checking what is present in your params hash
|
16
|
+
against the attributes of your model.
|
17
|
+
|
18
|
+
Since it returns an instance of ActiveRecord_Relation, you can chain other scopes/methods if you
|
19
|
+
so desire.
|
20
|
+
|
21
|
+
Currently compatible with Sqlite3 and PostgreSQL.
|
22
|
+
|
23
|
+
### When should I use this?
|
24
|
+
|
25
|
+
When coming up with simple search features for a given application.
|
26
|
+
|
27
|
+
### What is this capable of doing?
|
28
|
+
|
29
|
+
Below is what's currently doable:
|
30
|
+
- Search for specific attributes (by passing a params hash where the key is your attribute name and
|
31
|
+
the value is what you're looking for).
|
32
|
+
- Hit the database with a query containing LIKE for all attributes not present in the BLACK_LIST (or present in the WHITE_LIST) and using
|
33
|
+
a value stored in your params[:search] key.
|
34
|
+
- Hit the database with a query containing LIKE and the operator = for all attributes not present in the BLACK_LIST (or present in the WHITE_LIST)
|
35
|
+
and using a value stored in your params[:search] key and a key for one of your attributes (params[:name], for the example of a class User).
|
36
|
+
|
37
|
+
PS: The DEFAULT_BLACK_LIST contains the attributes :id, :created_at and :updated_at. You can pass your own
|
38
|
+
DEFAULT_BLACK_LIST when calling the #search method from your model, but I recommend using the WHITE_LIST,
|
39
|
+
as SeekParty will then only generate queries using the column names present there.
|
40
|
+
|
41
|
+
## Getting started
|
42
|
+
|
43
|
+
### Instalation
|
44
|
+
|
45
|
+
Add the following to your Gemfile
|
46
|
+
|
47
|
+
``` ruby
|
48
|
+
gem 'seek_party', '~> 0.0.1'
|
49
|
+
```
|
50
|
+
Then run:
|
51
|
+
|
52
|
+
``` shell
|
53
|
+
bundle install
|
54
|
+
```
|
55
|
+
|
56
|
+
Add the SeekParty functionality to your model:
|
57
|
+
|
58
|
+
``` ruby
|
59
|
+
class User < ApplicationRecord
|
60
|
+
extend SeekParty
|
61
|
+
...
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
## Usage
|
66
|
+
|
67
|
+
Given a User model like the following:
|
68
|
+
|
69
|
+
``` ruby
|
70
|
+
create_table :users, force: true do |t|
|
71
|
+
t.string :name
|
72
|
+
t.string :email
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
You could search the table like so:
|
77
|
+
|
78
|
+
``` ruby
|
79
|
+
params = {search: 'bilbo'}
|
80
|
+
User.search(params: params)
|
81
|
+
```
|
82
|
+
|
83
|
+
PS: The params hash can be either created by you or you can pass the ActionController::Parameters
|
84
|
+
instance that is available at the controller level.
|
85
|
+
|
86
|
+
And it would produce the following query for Sqlite3:
|
87
|
+
|
88
|
+
``` sql
|
89
|
+
SELECT "users".* FROM "users" WHERE (LOWER(CAST(name AS TEXT)) LIKE '%bilbo%' OR LOWER(CAST(email AS TEXT)) LIKE '%bilbo%')
|
90
|
+
```
|
91
|
+
|
92
|
+
As you can see, it took all of the attributes into consideration when generating the
|
93
|
+
query. But you can also limit what's going to be used to build such query by writing it
|
94
|
+
in the following way:
|
95
|
+
|
96
|
+
``` ruby
|
97
|
+
params = {search: 'bilbo'}
|
98
|
+
User.search(params: params, white_list: ['name'])
|
99
|
+
```
|
100
|
+
|
101
|
+
Which would in turn produce the following query:
|
102
|
+
|
103
|
+
``` sql
|
104
|
+
SELECT "users".* FROM "users" WHERE (LOWER(CAST(name AS TEXT)) LIKE '%bilbo%')
|
105
|
+
```
|
106
|
+
|
107
|
+
If your params hash does not contain a search key, SeekParty will try to compare
|
108
|
+
the attributes in your model with the keys available in the params hash.
|
109
|
+
|
110
|
+
Which means that the following:
|
111
|
+
|
112
|
+
``` ruby
|
113
|
+
params = {name: 'bilbo'}
|
114
|
+
User.search(params: params)
|
115
|
+
```
|
116
|
+
|
117
|
+
Would produce a query like this:
|
118
|
+
``` sql
|
119
|
+
SELECT "users".* FROM "users" WHERE (LOWER(CAST(name AS TEXT)) = 'bilbo')
|
120
|
+
```
|
121
|
+
|
122
|
+
SeekParty would use the equals operator instead of the LIKE, since it infers that
|
123
|
+
if you have keys in your params hash that match the attributes in your model, you basically
|
124
|
+
know what you are looking for.
|
125
|
+
|
126
|
+
But say that you are searching for a record for which you know one of the attributes for SURE,
|
127
|
+
but not the other(s). In this case, you could use both the search key as well as one key for
|
128
|
+
each one of your attributes like this:
|
129
|
+
|
130
|
+
|
131
|
+
``` ruby
|
132
|
+
params = {search: 'bilbo@theshire.com', name: 'bilbo'}
|
133
|
+
User.search(params: params)
|
134
|
+
```
|
135
|
+
|
136
|
+
And this would result in the following query being produced:
|
137
|
+
|
138
|
+
``` sql
|
139
|
+
SELECT "users".* FROM "users" WHERE (LOWER(CAST(name AS TEXT)) LIKE '%sugoi%' AND LOWER(CAST(name AS TEXT)) = 'bilbo' OR LOWER(CAST(email AS TEXT)) LIKE '%sugoi%' AND LOWER(CAST(name AS TEXT)) = 'bilbo')
|
140
|
+
```
|
141
|
+
|
142
|
+
### TO DO
|
143
|
+
|
144
|
+
- Write more tests
|
145
|
+
- Improve code quality
|
146
|
+
- Add support to other adapters
|
147
|
+
|
148
|
+
## Development
|
149
|
+
|
150
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
151
|
+
|
152
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
153
|
+
|
154
|
+
## Contributing
|
155
|
+
|
156
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/caws/seek_party. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
157
|
+
|
158
|
+
## License
|
159
|
+
|
160
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
161
|
+
|
162
|
+
## Code of Conduct
|
163
|
+
|
164
|
+
Everyone interacting in the SeekParty project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/seek_party/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "seek_party"
|
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__)
|
data/bin/setup
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module SeekParty
|
2
|
+
class SeekPartyAttribute
|
3
|
+
attr_accessor :inspected_class,
|
4
|
+
:white_list,
|
5
|
+
:black_list
|
6
|
+
|
7
|
+
def initialize(inspected_class, white_list, black_list)
|
8
|
+
self.inspected_class = inspected_class
|
9
|
+
self.white_list = white_list
|
10
|
+
self.black_list = black_list
|
11
|
+
end
|
12
|
+
|
13
|
+
# Compare attributes to params passed
|
14
|
+
# If only search is present, query against all params
|
15
|
+
# If both search and other attributes match agains the
|
16
|
+
# params hash, query against them too.
|
17
|
+
def discover_attributes
|
18
|
+
check_attributes inspected_class.new
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def check_attributes(another_model)
|
24
|
+
return nil if another_model.nil?
|
25
|
+
|
26
|
+
attributes = []
|
27
|
+
another_model.attributes.keys.each do |attribute|
|
28
|
+
next unless another_model.has_attribute? attribute
|
29
|
+
next if black_listed? attribute
|
30
|
+
|
31
|
+
attributes << attribute if white_listed? attribute
|
32
|
+
end
|
33
|
+
|
34
|
+
attributes
|
35
|
+
end
|
36
|
+
|
37
|
+
def white_listed?(attribute_name)
|
38
|
+
return true if white_list.nil?
|
39
|
+
|
40
|
+
white_list.include? attribute_name
|
41
|
+
end
|
42
|
+
|
43
|
+
def black_listed?(attribute_name)
|
44
|
+
black_list.include? attribute_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SeekParty
|
2
|
+
class SeekPartyEngine
|
3
|
+
attr_accessor :seek_party_attribute,
|
4
|
+
:seek_party_query,
|
5
|
+
:inspected_class
|
6
|
+
|
7
|
+
def initialize(inspected_class, params: {}, white_list: nil, black_list: nil, scopes: {})
|
8
|
+
@seek_party_attribute = SeekPartyAttribute.new(inspected_class, white_list, black_list)
|
9
|
+
@seek_party_query = SeekPartyQuery.new(params)
|
10
|
+
@inspected_class = inspected_class
|
11
|
+
@scopes = scopes
|
12
|
+
end
|
13
|
+
|
14
|
+
def search
|
15
|
+
attributes = seek_party_attribute.discover_attributes
|
16
|
+
final_query = seek_party_query.build_query(attributes)
|
17
|
+
run_search(final_query)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def run_search(final_query)
|
23
|
+
# If scopes were passed, iterate trough\ them.
|
24
|
+
setup_scopes if @scopes
|
25
|
+
|
26
|
+
# Execute final query (alongside any scopes that have been passed)
|
27
|
+
@inspected_class.where(final_query)
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_scopes
|
31
|
+
# Iterate trough the scopes that may have been
|
32
|
+
# passed. PS: This is more of a luxury than anything
|
33
|
+
# else, as the returned object from run_search is an
|
34
|
+
# ActiveRecord_Relation object that would accept
|
35
|
+
# method chaining
|
36
|
+
@scopes.each do |key, value|
|
37
|
+
@inspected_class = @inspected_class.method(key).call(value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module SeekParty
|
2
|
+
class SeekPartyQuery
|
3
|
+
|
4
|
+
attr_accessor :params,
|
5
|
+
:queries
|
6
|
+
|
7
|
+
def initialize(params)
|
8
|
+
self.params = params
|
9
|
+
self.queries = ({})
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_query(attributes)
|
13
|
+
return unless params
|
14
|
+
|
15
|
+
build_base_queries(attributes)
|
16
|
+
build_final_query
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def build_subquery_string(attribute, attribute_deep)
|
22
|
+
if params[:search].present?
|
23
|
+
queries[attribute] << " AND #{cast_according_to_adapter(attribute_deep)} = "\
|
24
|
+
"'#{params[attribute_deep.to_sym].to_s.downcase}'"
|
25
|
+
else
|
26
|
+
queries[attribute_deep] = "#{cast_according_to_adapter(attribute_deep)} = "\
|
27
|
+
"'#{params[attribute_deep.to_sym].to_s.downcase}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_base_queries(attributes)
|
32
|
+
attributes.each do |attribute|
|
33
|
+
if params[:search].present?
|
34
|
+
queries[attribute] = "#{cast_according_to_adapter(attribute)} LIKE "\
|
35
|
+
"'%#{params[:search].downcase}%'"
|
36
|
+
end
|
37
|
+
|
38
|
+
# If there are other params being used other than :search
|
39
|
+
# it means a where clause is needed.
|
40
|
+
# TODO: Figure out a way to work with date intervals, too.
|
41
|
+
attributes.each do |attribute_deep|
|
42
|
+
next unless params[attribute_deep.to_sym]
|
43
|
+
|
44
|
+
build_subquery_string(attribute, attribute_deep)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_final_query
|
50
|
+
final_query = ''
|
51
|
+
queries.each do |_key, value|
|
52
|
+
next unless value
|
53
|
+
|
54
|
+
final_query << if value == queries[queries.keys.first]
|
55
|
+
value
|
56
|
+
else
|
57
|
+
params[:search].present? ? " OR #{value}" : " AND #{value}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
final_query
|
62
|
+
end
|
63
|
+
|
64
|
+
def cast_according_to_adapter(column_name)
|
65
|
+
if db_sqlite3?
|
66
|
+
"LOWER(CAST(#{column_name} AS TEXT))"
|
67
|
+
elsif db_postgresql?
|
68
|
+
"LOWER(#{column_name}::VARCHAR)"
|
69
|
+
else
|
70
|
+
raise "SeekParty does not support #{ActiveRecord::Base.connection.class}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def db_sqlite3?
|
75
|
+
ActiveRecord::Base.connection.instance_of? ActiveRecord::ConnectionAdapters::SQLite3Adapter
|
76
|
+
rescue StandardError
|
77
|
+
false
|
78
|
+
end
|
79
|
+
|
80
|
+
def db_postgresql?
|
81
|
+
ActiveRecord::Base.connection.instance_of? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
82
|
+
rescue StandardError
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/seek_party.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_record' unless defined? ActiveRecord
|
2
|
+
require_relative 'seek_party/seek_party_attribute'
|
3
|
+
require_relative 'seek_party/seek_party_engine'
|
4
|
+
require_relative 'seek_party/seek_party_query'
|
5
|
+
require_relative 'seek_party/version'
|
6
|
+
|
7
|
+
module SeekParty
|
8
|
+
DEFAULT_BLACK_LIST = %w[id created_at updated_at].freeze
|
9
|
+
|
10
|
+
# Method below triggers all the magic
|
11
|
+
def search(params: [],
|
12
|
+
black_list: DEFAULT_BLACK_LIST,
|
13
|
+
white_list: nil,
|
14
|
+
scopes: [])
|
15
|
+
# If there are params to work with, use SeekParty.
|
16
|
+
# Otherwise, just return an empty instance of ActiveRecord_Relation.
|
17
|
+
return none if params.empty?
|
18
|
+
|
19
|
+
SeekPartyEngine
|
20
|
+
.new(self,
|
21
|
+
params: params,
|
22
|
+
white_list: white_list,
|
23
|
+
black_list: black_list,
|
24
|
+
scopes: scopes)
|
25
|
+
.search
|
26
|
+
end
|
27
|
+
end
|
data/seek_party.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "seek_party/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "seek_party"
|
7
|
+
spec.version = SeekParty::VERSION
|
8
|
+
spec.authors = ["Charles Washington"]
|
9
|
+
spec.email = ["charles_was_7@hotmail.com"]
|
10
|
+
|
11
|
+
spec.summary = %q{SeekParty makes quick work of adding search functionalities to your models.}
|
12
|
+
spec.description = %q{This gem should be used alongside ActiveRecord and uses introspection in order to check the fields of a given model. }
|
13
|
+
spec.homepage = "https://github.com/caws/seek_party"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
17
|
+
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/caws/seek_party"
|
20
|
+
spec.metadata["changelog_uri"] = "https://github.com/caws/seek_party"
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
end
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
32
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: seek_party
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Charles Washington
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-12-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: 'This gem should be used alongside ActiveRecord and uses introspection
|
56
|
+
in order to check the fields of a given model. '
|
57
|
+
email:
|
58
|
+
- charles_was_7@hotmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rakeTasks"
|
65
|
+
- ".rspec"
|
66
|
+
- CODE_OF_CONDUCT.md
|
67
|
+
- Gemfile
|
68
|
+
- Gemfile.lock
|
69
|
+
- LICENSE.txt
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- bin/console
|
73
|
+
- bin/setup
|
74
|
+
- lib/seek_party.rb
|
75
|
+
- lib/seek_party/seek_party_attribute.rb
|
76
|
+
- lib/seek_party/seek_party_engine.rb
|
77
|
+
- lib/seek_party/seek_party_query.rb
|
78
|
+
- lib/seek_party/version.rb
|
79
|
+
- seek_party.gemspec
|
80
|
+
homepage: https://github.com/caws/seek_party
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata:
|
84
|
+
homepage_uri: https://github.com/caws/seek_party
|
85
|
+
source_code_uri: https://github.com/caws/seek_party
|
86
|
+
changelog_uri: https://github.com/caws/seek_party
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubygems_version: 3.0.3
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: SeekParty makes quick work of adding search functionalities to your models.
|
106
|
+
test_files: []
|