active_hash_relation 1.1.0 → 1.2.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/.rspec +2 -0
- data/.travis.yml +15 -0
- data/README.md +68 -11
- data/active_hash_relation.gemspec +13 -0
- data/lib/active_hash_relation.rb +18 -12
- data/lib/active_hash_relation/aggregation.rb +3 -0
- data/lib/active_hash_relation/association_filters.rb +3 -0
- data/lib/active_hash_relation/column_filters.rb +45 -11
- data/lib/active_hash_relation/filter_applier.rb +37 -23
- data/lib/active_hash_relation/helpers.rb +22 -2
- data/lib/active_hash_relation/scope_filters.rb +8 -1
- data/lib/active_hash_relation/sort_filters.rb +12 -0
- data/lib/active_hash_relation/version.rb +1 -1
- data/lib/active_record/scope_names.rb +4 -19
- data/lib/generators/active_hash_relation/initialize_generator.rb +13 -0
- data/lib/generators/active_hash_relation/templates/active_hash_relation.rb +12 -0
- data/spec/config/initializers/active_hash_relation.rb +16 -0
- data/spec/db/migrate/001_basic_schema.rb +53 -0
- data/spec/dummy-rails4/.gitignore +13 -0
- data/spec/dummy-rails4/.ruby-version +1 -0
- data/spec/dummy-rails4/Gemfile +18 -0
- data/spec/dummy-rails4/README.md +3 -0
- data/spec/dummy-rails4/Rakefile +6 -0
- data/spec/dummy-rails4/app/controllers/application_controller.rb +5 -0
- data/spec/dummy-rails4/app/models/.keep +0 -0
- data/spec/dummy-rails4/app/models/address.rb +1 -0
- data/spec/dummy-rails4/app/models/micropost.rb +1 -0
- data/spec/dummy-rails4/app/models/relationship.rb +1 -0
- data/spec/dummy-rails4/app/models/user.rb +1 -0
- data/spec/dummy-rails4/bin/bundle +3 -0
- data/spec/dummy-rails4/bin/rails +4 -0
- data/spec/dummy-rails4/bin/rake +4 -0
- data/spec/dummy-rails4/bin/setup +29 -0
- data/spec/dummy-rails4/config.ru +4 -0
- data/spec/dummy-rails4/config/application.rb +35 -0
- data/spec/dummy-rails4/config/boot.rb +3 -0
- data/spec/dummy-rails4/config/database.yml +18 -0
- data/spec/dummy-rails4/config/environment.rb +5 -0
- data/spec/dummy-rails4/config/environments/development.rb +41 -0
- data/spec/dummy-rails4/config/environments/production.rb +79 -0
- data/spec/dummy-rails4/config/environments/test.rb +42 -0
- data/spec/dummy-rails4/config/initializers/active_hash_relation.rb +3 -0
- data/spec/dummy-rails4/config/initializers/assets.rb +11 -0
- data/spec/dummy-rails4/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy-rails4/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy-rails4/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy-rails4/config/initializers/inflections.rb +16 -0
- data/spec/dummy-rails4/config/initializers/mime_types.rb +4 -0
- data/spec/dummy-rails4/config/initializers/session_store.rb +3 -0
- data/spec/dummy-rails4/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy-rails4/config/locales/en.yml +23 -0
- data/spec/dummy-rails4/config/routes.rb +56 -0
- data/spec/dummy-rails4/config/secrets.yml +22 -0
- data/spec/dummy-rails4/db/migrate/001_basic_schema.rb +1 -0
- data/spec/dummy-rails4/db/schema.rb +69 -0
- data/spec/dummy-rails4/spec/factories/factories.rb +1 -0
- data/spec/dummy-rails4/spec/rails_helper.rb +19 -0
- data/spec/dummy-rails4/spec/spec_helper.rb +99 -0
- data/spec/dummy-rails4/spec/support/support.rb +1 -0
- data/spec/dummy-rails4/spec/tests/tests_spec.rb +3 -0
- data/spec/dummy-rails5/.gitignore +17 -0
- data/spec/dummy-rails5/.rspec +2 -0
- data/spec/dummy-rails5/.ruby-version +1 -0
- data/spec/dummy-rails5/Gemfile +19 -0
- data/spec/dummy-rails5/README.md +3 -0
- data/spec/dummy-rails5/Rakefile +6 -0
- data/spec/dummy-rails5/app/controllers/application_controller.rb +3 -0
- data/spec/dummy-rails5/app/models/address.rb +1 -0
- data/spec/dummy-rails5/app/models/micropost.rb +1 -0
- data/spec/dummy-rails5/app/models/relationship.rb +1 -0
- data/spec/dummy-rails5/app/models/user.rb +1 -0
- data/spec/dummy-rails5/bin/bundle +3 -0
- data/spec/dummy-rails5/bin/rails +4 -0
- data/spec/dummy-rails5/bin/rake +4 -0
- data/spec/dummy-rails5/bin/setup +34 -0
- data/spec/dummy-rails5/bin/update +29 -0
- data/spec/dummy-rails5/config.ru +5 -0
- data/spec/dummy-rails5/config/application.rb +25 -0
- data/spec/dummy-rails5/config/boot.rb +3 -0
- data/spec/dummy-rails5/config/cable.yml +9 -0
- data/spec/dummy-rails5/config/database.yml +18 -0
- data/spec/dummy-rails5/config/environment.rb +5 -0
- data/spec/dummy-rails5/config/environments/development.rb +54 -0
- data/spec/dummy-rails5/config/environments/production.rb +86 -0
- data/spec/dummy-rails5/config/environments/test.rb +42 -0
- data/spec/dummy-rails5/config/initializers/active_hash_relation.rb +3 -0
- data/spec/dummy-rails5/config/initializers/application_controller_renderer.rb +6 -0
- data/spec/dummy-rails5/config/initializers/assets.rb +11 -0
- data/spec/dummy-rails5/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy-rails5/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy-rails5/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy-rails5/config/initializers/inflections.rb +16 -0
- data/spec/dummy-rails5/config/initializers/mime_types.rb +4 -0
- data/spec/dummy-rails5/config/initializers/new_framework_defaults.rb +24 -0
- data/spec/dummy-rails5/config/initializers/session_store.rb +3 -0
- data/spec/dummy-rails5/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy-rails5/config/locales/en.yml +23 -0
- data/spec/dummy-rails5/config/puma.rb +47 -0
- data/spec/dummy-rails5/config/routes.rb +3 -0
- data/spec/dummy-rails5/config/secrets.yml +22 -0
- data/spec/dummy-rails5/config/spring.rb +6 -0
- data/spec/dummy-rails5/db/migrate/001_basic_schema.rb +2 -0
- data/spec/dummy-rails5/db/schema.rb +64 -0
- data/spec/dummy-rails5/spec/factories/factories.rb +1 -0
- data/spec/dummy-rails5/spec/rails_helper.rb +19 -0
- data/spec/dummy-rails5/spec/spec_helper.rb +99 -0
- data/spec/dummy-rails5/spec/support/support.rb +1 -0
- data/spec/dummy-rails5/spec/tests/tests_spec.rb +3 -0
- data/spec/factories/factories.rb +39 -0
- data/spec/models/address.rb +7 -0
- data/spec/models/application_record.rb +3 -0
- data/spec/models/micropost.rb +9 -0
- data/spec/models/relationship.rb +9 -0
- data/spec/models/user.rb +32 -0
- data/spec/support/support.rb +62 -0
- data/spec/tests/aggregations/avg_spec.rb +45 -0
- data/spec/tests/aggregations/max_spec.rb +45 -0
- data/spec/tests/aggregations/min_spec.rb +46 -0
- data/spec/tests/aggregations/sum_spec.rb +43 -0
- data/spec/tests/associations/belongs_to_spec.rb +96 -0
- data/spec/tests/associations/has_many_spec.rb +91 -0
- data/spec/tests/associations/has_one_spec.rb +89 -0
- data/spec/tests/booleans_spec.rb +29 -0
- data/spec/tests/limit_spec.rb +30 -0
- data/spec/tests/null_spec.rb +44 -0
- data/spec/tests/numbers_spec.rb +142 -0
- data/spec/tests/or_filter_spec.rb +98 -0
- data/spec/tests/primary_key_spec.rb +29 -0
- data/spec/tests/scopes_spec.rb +48 -0
- data/spec/tests/sorting_spec.rb +100 -0
- data/spec/tests/strings_spec.rb +86 -0
- metadata +392 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a59228314ab4ecac89c7ba2f988514e453d2b434
|
|
4
|
+
data.tar.gz: 16316aba61f2ff203189607d69fd9e738649187d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 67342eb6d946bea38b57f1b3e1f99f389c815fef0f6c89445c806ccde2750b18b33810d8cf60ac7b982281de08ad3564f329147d9d6b18be31070345a64f445e
|
|
7
|
+
data.tar.gz: aa938f3c84a0054be00d9af1fe80cda17ef4a9e0f249bd4d91a23d065230d3052cb7f8da81a215171d54e4226c959bc0fe7cefad328be807ea0977f914e27998
|
data/.rspec
ADDED
data/.travis.yml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
sudo: false
|
|
3
|
+
rvm: 2.3.3
|
|
4
|
+
cache:
|
|
5
|
+
bundler: true
|
|
6
|
+
install:
|
|
7
|
+
- cd spec/dummy-rails4 && bundle install
|
|
8
|
+
- cd ../dummy-rails5 && bundle install
|
|
9
|
+
script:
|
|
10
|
+
- echo $(pwd)
|
|
11
|
+
- cd ../dummy-rails4 && bundle exec rspec spec/
|
|
12
|
+
- echo $(pwd)
|
|
13
|
+
- cd ../dummy-rails5 && bundle exec rspec spec/
|
|
14
|
+
notifications:
|
|
15
|
+
email: false
|
data/README.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# ActiveHashRelation
|
|
2
|
+
[ ](https://app.codeship.com/projects/200194)
|
|
2
3
|
|
|
3
4
|
## Introduction
|
|
4
5
|
Simple gem that allows you to manipulate ActiveRecord::Relation using JSON. For instance:
|
|
@@ -11,7 +12,7 @@ apply_filters(resource, {updated_at: { geq: "2014-11-2 14:25:04"}, unit: {id: 9}
|
|
|
11
12
|
```
|
|
12
13
|
or even filter a resource based on it's associations' associations:
|
|
13
14
|
```ruby
|
|
14
|
-
apply_filters(resource, {updated_at: { geq: "2014-11-2 14:25:04"}, unit: {id: 9, areas: {id: 22} }})
|
|
15
|
+
apply_filters(resource, {updated_at: { geq: "2014-11-2 14:25:04"}, unit: {id: 9, areas: {or: [{id: 22}, {id: 21}]} }})
|
|
15
16
|
```
|
|
16
17
|
and the list could go on.. Basically your whole db is exposed\* there. It's perfect for filtering a collection of resources on APIs.
|
|
17
18
|
|
|
@@ -29,7 +30,7 @@ which might or might not be a security issue. If you don't like that check
|
|
|
29
30
|
|
|
30
31
|
Add this line to your application's Gemfile:
|
|
31
32
|
|
|
32
|
-
gem 'active_hash_relation'
|
|
33
|
+
gem 'active_hash_relation', '~> 1.2.0
|
|
33
34
|
|
|
34
35
|
And then execute:
|
|
35
36
|
|
|
@@ -38,8 +39,10 @@ And then execute:
|
|
|
38
39
|
Or install it yourself as:
|
|
39
40
|
|
|
40
41
|
$ gem install active_hash_relation
|
|
42
|
+
|
|
41
43
|
## How to use
|
|
42
|
-
The gem exposes only one method: `apply_filters(resource, hash_params, include_associations: true, model: nil)`.
|
|
44
|
+
The gem exposes only one method: `apply_filters(resource, hash_params, include_associations: true, model: nil)`.
|
|
45
|
+
`resource` is expected to be an ActiveRecord::Relation.
|
|
43
46
|
That way, you can add your custom filters before passing the `Relation` to `ActiveHashRelation`.
|
|
44
47
|
|
|
45
48
|
In order to use it you have to include ActiveHashRelation module in your class. For instance in a Rails API controller you would do:
|
|
@@ -58,21 +61,40 @@ class Api::V1::ResourceController < Api::V1::BaseController
|
|
|
58
61
|
end
|
|
59
62
|
```
|
|
60
63
|
|
|
64
|
+
If you **need to enable filtering on scopes**, you need to specify that explicitly from the initializer. For instance:
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
ActiveHashRelation.configure do |config|
|
|
68
|
+
#override default scope when accessing associations
|
|
69
|
+
config.use_unscoped = true
|
|
70
|
+
#set true to be able to filter scopes (with params)
|
|
71
|
+
#please note that unfortunately (:/) rails does not provide any way
|
|
72
|
+
#to iterate through scopes so it uses a monkey patch.
|
|
73
|
+
#The monkey patch is as gentle as it can be by aliasing the method, adds some
|
|
74
|
+
#sugar and calls it,
|
|
75
|
+
#You need to run `initialize!` to actually include the required files
|
|
76
|
+
config.filter_active_record_scopes = true
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
#requires monkeyparched scopes, optional if you don't enable them
|
|
80
|
+
ActiveHashRelation.initialize!
|
|
81
|
+
```
|
|
82
|
+
|
|
61
83
|
## The API
|
|
62
84
|
### Columns
|
|
63
|
-
For each param, `apply_filters` method will search in the model's (derived from the
|
|
85
|
+
For each param, `apply_filters` method will search in the model's (derived from the
|
|
86
|
+
first param, or explicitly defined as the last param) all the record's column names
|
|
87
|
+
and associations. (filtering based on scopes are not working at the moment but
|
|
88
|
+
will be supported soon). For each column, if there is such a param, it will
|
|
89
|
+
apply the filter based on the column type. The following column types are supported:
|
|
64
90
|
|
|
65
|
-
#### Primary
|
|
66
|
-
You can apply a filter a column which is a primary key by value or using an array like:
|
|
67
|
-
* `{primary_key_column: 5}`
|
|
68
|
-
* `{primary_key_column: [1,3,4,5,6,7]}`
|
|
69
91
|
|
|
70
92
|
#### Integer, Float, Decimal, Date, Time or Datetime/Timestamp
|
|
71
93
|
You can apply an equality filter:
|
|
72
94
|
|
|
73
95
|
* `{example_column: 500}`
|
|
74
96
|
|
|
75
|
-
or using an array
|
|
97
|
+
or using an array (`ActiveRecord` translates that internally to an `IN` query)
|
|
76
98
|
* `{example_column: [500, 40]}`
|
|
77
99
|
|
|
78
100
|
or using a hash as a value you get more options:
|
|
@@ -100,7 +122,13 @@ or using a hash as a value you get more options:
|
|
|
100
122
|
* `{example_column: {eq: 'exact value'}}` `#runs: EXAMPLE_COLUMN = 'test'`
|
|
101
123
|
* `{example_column: {starts_with: 'exac'}}` `#runs: EXAMPLE_COLUMN LIKE 'test%'`
|
|
102
124
|
* `{example_column: {ends_with: 'alue'}}` `#runs: EXAMPLE_COLUMN LIKE '%test'`
|
|
103
|
-
* `{example_column: {like: 'ct_va}}` `#runs: EXAMPLE_COLUMN LIKE '%test%'`
|
|
125
|
+
* `{example_column: {like: 'ct_va'}}` `#runs: EXAMPLE_COLUMN LIKE '%test%'`
|
|
126
|
+
|
|
127
|
+
If you want to filter using `ILIKE` you can pass an `with_ilike` param:
|
|
128
|
+
|
|
129
|
+
* `{example_column: {like: 'ct_va', with_ilike: true}}` `#runs: EXAMPLE_COLUMN ILIKE '%test%'`
|
|
130
|
+
* `{example_column: {like: 'ct_va', with_ilike: true}}` `#runs: EXAMPLE_COLUMN ILIKE '%test%'`
|
|
131
|
+
|
|
104
132
|
|
|
105
133
|
**Please note that ILIKE and especially LIKE are quite slow if you have millions of records in the db even with an index.**
|
|
106
134
|
|
|
@@ -129,12 +157,41 @@ micropost_filter = Micropost.all.where("CREATED_AT =< ?", '12-9-2014'.to_datetim
|
|
|
129
157
|
User.where(email: 'test@user.com').joins(:microposts).merge(micropost_filter)
|
|
130
158
|
```
|
|
131
159
|
|
|
160
|
+
### NULL Filter
|
|
161
|
+
You can apply null filter for generate query like this `"users.name IS NULL"` or `"users.name IS NOT NULL"` with this following code:
|
|
162
|
+
`{ name: { null: true } }` for is null filter and `{ name: { null: false } }` for not null filter.
|
|
163
|
+
|
|
164
|
+
this can be used also for relations tables, so you can write like this `{ books: {title: {null: false }} }`
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
### OR Filter
|
|
168
|
+
You can apply an SQL `OR` (for ActiveRecord 5+) using the following syntax:
|
|
169
|
+
`{or: [{name: 'Filippos'}, {name: 'Vasilis'}]}`
|
|
170
|
+
|
|
171
|
+
It will generate: `WHERE ((users.name = 'Filippos') OR (users.name = 'Vasilis'))`
|
|
172
|
+
|
|
173
|
+
You can apply an `OR` on associations as well or even nested ones, there isn't much limitation on that.
|
|
174
|
+
I suggest you though to take a look on the [tests](spec/tests/or_filter_spec.rb), cause the syntax gets a bit complex after a while ;)
|
|
175
|
+
|
|
176
|
+
|
|
132
177
|
### Scopes
|
|
133
|
-
|
|
178
|
+
**Filtering on scopes is not enabled by default**.
|
|
179
|
+
|
|
180
|
+
Scopes are supported via a tiny monkeypatch in the ActiveRecord's scope class method which holds the name of each scope.
|
|
181
|
+
The monkey patch is as gentle as it can be: it aliases the method, adds some sugar and executes it.
|
|
182
|
+
|
|
183
|
+
Scopes with arguments are also supported but not tested much. Probably they will work fine unless your arguments expect
|
|
184
|
+
complex objects.
|
|
185
|
+
|
|
186
|
+
If you want to filter based on a scope in a model, the scope names should go under `scopes` sub-hash. For instance the following:
|
|
134
187
|
* `{ scopes: { planned: true } }`
|
|
135
188
|
|
|
136
189
|
will run the `.planned` scope on the resource.
|
|
137
190
|
|
|
191
|
+
* `{scopes: {created_between: [1988, 2018]}}`
|
|
192
|
+
|
|
193
|
+
will run the `.created_on(1988, 2018)` scope on the resource.
|
|
194
|
+
|
|
138
195
|
### Unscoped assotiations
|
|
139
196
|
If you have a default scope in your models and you have a good reason to keep that, `active_hash_relation` provides an option to override it when filtering associations:
|
|
140
197
|
|
|
@@ -18,6 +18,19 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
+
spec.add_runtime_dependency "activerecord"
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "activerecord"
|
|
21
24
|
spec.add_development_dependency "bundler", "~> 1.6"
|
|
22
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
|
26
|
+
|
|
27
|
+
spec.add_development_dependency 'rspec'
|
|
28
|
+
spec.add_development_dependency "factory_girl_rails", "~> 4.0"
|
|
29
|
+
spec.add_development_dependency 'faker'
|
|
30
|
+
spec.add_development_dependency 'database_cleaner'
|
|
31
|
+
spec.add_development_dependency 'pry'
|
|
32
|
+
spec.add_development_dependency 'sqlite3'
|
|
33
|
+
spec.add_development_dependency 'pg'
|
|
34
|
+
spec.add_development_dependency 'rails'
|
|
35
|
+
spec.add_development_dependency 'rspec-rails'
|
|
23
36
|
end
|
data/lib/active_hash_relation.rb
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
require "active_hash_relation/aggregation"
|
|
1
|
+
require_relative "active_hash_relation/version"
|
|
2
|
+
require_relative "active_hash_relation/helpers"
|
|
3
|
+
require_relative "active_hash_relation/column_filters"
|
|
4
|
+
require_relative "active_hash_relation/scope_filters"
|
|
5
|
+
require_relative "active_hash_relation/sort_filters"
|
|
6
|
+
require_relative "active_hash_relation/limit_filters"
|
|
7
|
+
require_relative "active_hash_relation/association_filters"
|
|
8
|
+
require_relative "active_hash_relation/filter_applier"
|
|
9
|
+
|
|
10
|
+
require_relative "active_hash_relation/aggregation"
|
|
12
11
|
|
|
13
12
|
module ActiveHashRelation
|
|
14
13
|
class << self
|
|
@@ -23,6 +22,13 @@ module ActiveHashRelation
|
|
|
23
22
|
def self.configuration
|
|
24
23
|
@configuration ||= Configuration.new do
|
|
25
24
|
self.has_filter_classes = false
|
|
25
|
+
self.filter_active_record_scopes = false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.initialize!
|
|
30
|
+
if self.configuration.filter_active_record_scopes
|
|
31
|
+
require_relative "active_record/scope_names"
|
|
26
32
|
end
|
|
27
33
|
end
|
|
28
34
|
|
|
@@ -41,6 +47,6 @@ module ActiveHashRelation
|
|
|
41
47
|
|
|
42
48
|
class Configuration
|
|
43
49
|
attr_accessor :has_filter_classes, :filter_class_prefix, :filter_class_suffix,
|
|
44
|
-
:use_unscoped
|
|
50
|
+
:use_unscoped, :filter_active_record_scopes
|
|
45
51
|
end
|
|
46
52
|
end
|
|
@@ -2,6 +2,9 @@ module ActiveHashRelation::AssociationFilters
|
|
|
2
2
|
def filter_associations(resource, params, model = nil)
|
|
3
3
|
unless model
|
|
4
4
|
model = model_class_name(resource)
|
|
5
|
+
if model.nil? || engine_name == model.to_s
|
|
6
|
+
model = model_class_name(resource, true)
|
|
7
|
+
end
|
|
5
8
|
end
|
|
6
9
|
|
|
7
10
|
model.reflect_on_all_associations.map(&:name).each do |association|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module ActiveHashRelation::ColumnFilters
|
|
2
|
-
def filter_primary(resource, column, param)
|
|
3
|
-
resource = resource.where(id: param)
|
|
4
|
-
end
|
|
5
|
-
|
|
6
2
|
def filter_integer(resource, column, table_name, param)
|
|
7
3
|
if param.is_a? Array
|
|
8
4
|
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
|
|
9
5
|
return resource.where("#{table_name}.#{column} IN (#{n_param})")
|
|
10
6
|
elsif param.is_a? Hash
|
|
11
|
-
|
|
7
|
+
if !param[:null].nil?
|
|
8
|
+
return null_filters(resource, table_name, column, param)
|
|
9
|
+
else
|
|
10
|
+
return apply_leq_geq_le_ge_filters(resource, table_name, column, param)
|
|
11
|
+
end
|
|
12
12
|
else
|
|
13
13
|
return resource.where("#{table_name}.#{column} = ?", param)
|
|
14
14
|
end
|
|
@@ -27,7 +27,11 @@ module ActiveHashRelation::ColumnFilters
|
|
|
27
27
|
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
|
|
28
28
|
return resource.where("#{table_name}.#{column} IN (#{n_param})")
|
|
29
29
|
elsif param.is_a? Hash
|
|
30
|
-
|
|
30
|
+
if !param[:null].nil?
|
|
31
|
+
return null_filters(resource, table_name, column, param)
|
|
32
|
+
else
|
|
33
|
+
return apply_like_filters(resource, table_name, column, param)
|
|
34
|
+
end
|
|
31
35
|
else
|
|
32
36
|
return resource.where("#{table_name}.#{column} = ?", param)
|
|
33
37
|
end
|
|
@@ -42,7 +46,11 @@ module ActiveHashRelation::ColumnFilters
|
|
|
42
46
|
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
|
|
43
47
|
return resource.where("#{table_name}.#{column} IN (#{n_param})")
|
|
44
48
|
elsif param.is_a? Hash
|
|
45
|
-
|
|
49
|
+
if !param[:null].nil?
|
|
50
|
+
return null_filters(resource, table_name, column, param)
|
|
51
|
+
else
|
|
52
|
+
return apply_leq_geq_le_ge_filters(resource, table_name, column, param)
|
|
53
|
+
end
|
|
46
54
|
else
|
|
47
55
|
resource = resource.where(column => param)
|
|
48
56
|
end
|
|
@@ -55,7 +63,11 @@ module ActiveHashRelation::ColumnFilters
|
|
|
55
63
|
n_param = param.to_s.gsub("\"","'").gsub("[","").gsub("]","") #fix this!
|
|
56
64
|
return resource = resource.where("#{table_name}.#{column} IN (#{n_param})")
|
|
57
65
|
elsif param.is_a? Hash
|
|
58
|
-
|
|
66
|
+
if !param[:null].nil?
|
|
67
|
+
return null_filters(resource, table_name, column, param)
|
|
68
|
+
else
|
|
69
|
+
return apply_leq_geq_le_ge_filters(resource, table_name, column, param)
|
|
70
|
+
end
|
|
59
71
|
else
|
|
60
72
|
resource = resource.where(column => param)
|
|
61
73
|
end
|
|
@@ -63,15 +75,25 @@ module ActiveHashRelation::ColumnFilters
|
|
|
63
75
|
return resource
|
|
64
76
|
end
|
|
65
77
|
|
|
66
|
-
def filter_boolean(resource, column, param)
|
|
67
|
-
|
|
78
|
+
def filter_boolean(resource, column, table_name, param)
|
|
79
|
+
if param.is_a?(Hash) && !param[:null].nil?
|
|
80
|
+
return null_filters(resource, table_name, column, param)
|
|
81
|
+
else
|
|
82
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
|
83
|
+
b_param = ActiveRecord::Type::Boolean.new.cast(param)
|
|
84
|
+
else
|
|
85
|
+
b_param = ActiveRecord::Type::Boolean.new.type_cast_from_database(param)
|
|
86
|
+
end
|
|
68
87
|
|
|
69
|
-
|
|
88
|
+
resource = resource.where(column => b_param)
|
|
89
|
+
end
|
|
70
90
|
end
|
|
71
91
|
|
|
72
92
|
private
|
|
73
93
|
|
|
74
94
|
def apply_leq_geq_le_ge_filters(resource, table_name, column, param)
|
|
95
|
+
return resource.where("#{table_name}.#{column} = ?", param[:eq]) if param[:eq]
|
|
96
|
+
|
|
75
97
|
if !param[:leq].blank?
|
|
76
98
|
resource = resource.where("#{table_name}.#{column} <= ?", param[:leq])
|
|
77
99
|
elsif !param[:le].blank?
|
|
@@ -109,4 +131,16 @@ module ActiveHashRelation::ColumnFilters
|
|
|
109
131
|
|
|
110
132
|
return resource
|
|
111
133
|
end
|
|
134
|
+
|
|
135
|
+
def null_filters(resource, table_name, column, param)
|
|
136
|
+
if param[:null] == true
|
|
137
|
+
resource = resource.where("#{table_name}.#{column} IS NULL")
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
if param[:null] == false
|
|
141
|
+
resource = resource.where("#{table_name}.#{column} IS NOT NULL")
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
return resource
|
|
145
|
+
end
|
|
112
146
|
end
|
|
@@ -9,36 +9,26 @@ module ActiveHashRelation
|
|
|
9
9
|
|
|
10
10
|
attr_reader :configuration
|
|
11
11
|
|
|
12
|
-
def initialize(resource, params, include_associations:
|
|
12
|
+
def initialize(resource, params, include_associations: false, model: nil)
|
|
13
13
|
@configuration = Module.nesting.last.configuration
|
|
14
14
|
@resource = resource
|
|
15
|
-
|
|
15
|
+
if params.respond_to?(:to_unsafe_h)
|
|
16
|
+
@params = HashWithIndifferentAccess.new(params.to_unsafe_h)
|
|
17
|
+
else
|
|
18
|
+
@params = HashWithIndifferentAccess.new(params)
|
|
19
|
+
end
|
|
16
20
|
@include_associations = include_associations
|
|
17
|
-
@model = model
|
|
21
|
+
@model = find_model(model)
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
|
|
21
24
|
def apply_filters
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
end
|
|
25
|
+
run_or_filters
|
|
26
|
+
|
|
25
27
|
table_name = @model.table_name
|
|
26
28
|
@model.columns.each do |c|
|
|
27
29
|
next if @params[c.name.to_s].nil?
|
|
28
30
|
next if @params[c.name.to_s].is_a?(String) && @params[c.name.to_s].blank?
|
|
29
31
|
|
|
30
|
-
if c.respond_to?(:primary)
|
|
31
|
-
if c.primary
|
|
32
|
-
@resource = filter_primary(@resource, c.name, @params[c.name])
|
|
33
|
-
next
|
|
34
|
-
end
|
|
35
|
-
else #rails 4.2
|
|
36
|
-
if @model.primary_key == c.name
|
|
37
|
-
@resource = filter_primary(@resource, c.name, @params[c.name])
|
|
38
|
-
next
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
32
|
case c.type
|
|
43
33
|
when :integer
|
|
44
34
|
@resource = filter_integer(@resource, c.name, table_name, @params[c.name])
|
|
@@ -46,19 +36,24 @@ module ActiveHashRelation
|
|
|
46
36
|
@resource = filter_float(@resource, c.name, table_name, @params[c.name])
|
|
47
37
|
when :decimal
|
|
48
38
|
@resource = filter_decimal(@resource, c.name, table_name, @params[c.name])
|
|
49
|
-
when :string
|
|
39
|
+
when :string, :uuid, :text
|
|
50
40
|
@resource = filter_string(@resource, c.name, table_name, @params[c.name])
|
|
51
41
|
when :date
|
|
52
42
|
@resource = filter_date(@resource, c.name, table_name, @params[c.name])
|
|
53
43
|
when :datetime, :timestamp
|
|
54
44
|
@resource = filter_datetime(@resource, c.name, table_name, @params[c.name])
|
|
55
45
|
when :boolean
|
|
56
|
-
@resource = filter_boolean(@resource, c.name, @params[c.name])
|
|
46
|
+
@resource = filter_boolean(@resource, c.name, table_name, @params[c.name])
|
|
57
47
|
end
|
|
58
48
|
end
|
|
59
49
|
|
|
60
|
-
|
|
61
|
-
|
|
50
|
+
if @params.include?(:scopes)
|
|
51
|
+
if ActiveHashRelation.configuration.filter_active_record_scopes
|
|
52
|
+
@resource = filter_scopes(@resource, @params[:scopes], @model)
|
|
53
|
+
else
|
|
54
|
+
Rails.logger.warn('Ignoring ActiveRecord scope filters because they are not enabled')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
62
57
|
@resource = filter_associations(@resource, @params, @model) if @include_associations
|
|
63
58
|
@resource = apply_limit(@resource, @params[:limit]) if @params.include?(:limit)
|
|
64
59
|
@resource = apply_sort(@resource, @params[:sort], @model) if @params.include?(:sort)
|
|
@@ -69,5 +64,24 @@ module ActiveHashRelation
|
|
|
69
64
|
def filter_class(resource_name)
|
|
70
65
|
"#{configuration.filter_class_prefix}#{resource_name.pluralize}#{configuration.filter_class_suffix}".constantize
|
|
71
66
|
end
|
|
67
|
+
|
|
68
|
+
def run_or_filters
|
|
69
|
+
if @params[:or].is_a?(Array)
|
|
70
|
+
if ActiveRecord::VERSION::MAJOR < 5
|
|
71
|
+
return Rails.logger.warn("OR query is supported on ActiveRecord 5+")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
if @params[:or].length >= 2
|
|
75
|
+
array = @params[:or].map do |or_param|
|
|
76
|
+
self.class.new(@resource, or_param, include_associations: @include_associations).apply_filters
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
@resource = @resource.merge(array[0])
|
|
80
|
+
array[1..-1].each{|query| @resource = @resource.or(query)}
|
|
81
|
+
else
|
|
82
|
+
Rails.logger.warn("Can't run an OR with 1 element!")
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
72
86
|
end
|
|
73
87
|
end
|