active_hash_relation 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[ ![Codeship Status for kollegorna/active_hash_relation](https://app.codeship.com/projects/02f08850-cc66-0134-028f-5ad72e690a75/status?branch=master)](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
|