querii 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +21 -10
- data/lib/querii/query_object.rb +34 -18
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf2dcc2616587bd7e2f4533aa0675ac139c56fd1
|
4
|
+
data.tar.gz: 832407b904834d3d10adc3ef22acef6e93e41df2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc9da4056c84585c20338b699b61102874b3f95ebac86ab237b4967410bd4c4e859cea1d70e606f0c52da7b4dd8cb1c5e4306ab649fa44a0dc5500cb4e544661
|
7
|
+
data.tar.gz: f7dcc042f860a3575c79e8932a600dc615c6e3f25652f977de628ed38465b1af278ab3239751cb1b56faeca2a3ae106bfe3c6c2fe8d3211951fa0acb85251b18
|
data/README.md
CHANGED
@@ -6,7 +6,11 @@ Querii makes it easy to create query objects that return active record relations
|
|
6
6
|
|
7
7
|
## Why?
|
8
8
|
|
9
|
-
Querii allows you to extract complicated query collection logic out of
|
9
|
+
Querii allows you to extract complicated query collection logic out of an ActiveRecord model.
|
10
|
+
|
11
|
+
This prevents littering the base model and encourages breaking up your query logic into multiple methods, constants, etc. Querii creates a singleton that returns a standard activerecord collection (now extended by your additional querii scopes) that can be further acted upon.
|
12
|
+
|
13
|
+
This provides a pattern for extracting complicated common queries from your model or one off queries from a controller for easier testing and separation of concerns.
|
10
14
|
|
11
15
|
## Basic Usage
|
12
16
|
|
@@ -15,11 +19,9 @@ module Accounts
|
|
15
19
|
module FancySubset
|
16
20
|
include Querii::QueryObject
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
22
|
+
default_scope { where(cool: 'things') }
|
23
|
+
|
24
|
+
scope :filter, ->(hats: 2) { where(hats: hats) }
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
@@ -27,17 +29,26 @@ end
|
|
27
29
|
Accounts::FancySubset.call # or .all
|
28
30
|
|
29
31
|
# or more advanced chain
|
30
|
-
Accounts::FancySubset.call(hats: 4).where(typical: 'filtered')
|
32
|
+
Accounts::FancySubset.call.filter(hats: 4).where(typical: 'filtered')
|
31
33
|
# ...Account::ActiveRecord_Relation < ActiveRecord::Relation
|
32
34
|
```
|
33
35
|
|
34
|
-
|
36
|
+
### Base class
|
35
37
|
|
36
|
-
|
38
|
+
Querii infers the base model from the top level query object namespace. For the example above `Accounts` represents `Account`. You can easily override this by setting `self.model_name = 'ClassName'` within your query module.
|
37
39
|
|
38
40
|
### Default scope
|
39
41
|
|
40
|
-
|
42
|
+
A default scope is automatically defined for you with a collection of `.all`. You can set a customized default by calling `default_scope` and passing a block, proc, or lambda.
|
43
|
+
|
44
|
+
The default scope is designed for query objects that only contain a single base scope always intended to be called so you can simply do `MyQueryObj.call` or equivalently `MyQueryObj.all`.
|
45
|
+
|
46
|
+
### How it works
|
47
|
+
Querii dynamically defines a `Scopes` module when included that contains scopes defined either via `default_scope` or `scope :name, ->{}`. This pattern is taken from AR.
|
48
|
+
|
49
|
+
During a query this module is extended onto the base `ActiveRecord::Relation` and the defined default scope method is called. This returns an active record collection that can further be queried by both additional scopes defined within your Querii object and scopes or conditions on the base AR class.
|
50
|
+
|
51
|
+
Scopes can also be defined as methods explicitly by opening up the scopes class within your query object.
|
41
52
|
|
42
53
|
### Passing an already filtered relation
|
43
54
|
|
data/lib/querii/query_object.rb
CHANGED
@@ -5,36 +5,52 @@ module Querii
|
|
5
5
|
|
6
6
|
base.class_eval do
|
7
7
|
# dynamically defines a base Scopes module
|
8
|
-
self.const_set(
|
9
|
-
|
10
|
-
Module.new do
|
11
|
-
def applied(*args, **key_args)
|
12
|
-
all
|
13
|
-
end
|
14
|
-
end
|
15
|
-
)
|
8
|
+
self.const_set(:Scopes, Module.new)
|
9
|
+
default_scope { all }
|
16
10
|
end
|
17
11
|
end
|
18
12
|
|
19
13
|
module ClassMethods
|
20
|
-
|
21
|
-
|
14
|
+
# optionally override the default determined by top level namespace
|
15
|
+
attr_accessor :model_name
|
16
|
+
|
17
|
+
def call(*args, relation: base_class.all, **kargs)
|
18
|
+
relation.extending(self::Scopes).default(*args, **kargs)
|
22
19
|
end
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
alias_method :all, :call
|
22
|
+
|
23
|
+
def scope(name, body, &block)
|
24
|
+
unless body.respond_to?(:call)
|
25
|
+
raise ArgumentError, 'The scope body needs to be callable.'
|
26
|
+
end
|
27
|
+
|
28
|
+
self::Scopes.send(:define_method, name) do |*args, **kargs|
|
29
|
+
# unfortunately empty double splatted kargs still count as arguments
|
30
|
+
# for a lambda's argument arity checking
|
31
|
+
if kargs.empty?
|
32
|
+
scope = all.scoping { instance_exec(*args, &body) }
|
33
|
+
else
|
34
|
+
scope = all.scoping { instance_exec(*args, **kargs, &body) }
|
35
|
+
end
|
36
|
+
|
37
|
+
scope || all
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_scope(scope = nil)
|
42
|
+
scope = Proc.new if block_given?
|
43
|
+
scope(:default, scope)
|
27
44
|
end
|
28
45
|
|
29
46
|
# queries are namespaced by plural model name
|
30
47
|
# from which we can infer query base model
|
31
|
-
def
|
32
|
-
|
48
|
+
def base_class
|
49
|
+
klass = model_name || self.to_s.split('::').first.singularize
|
50
|
+
klass.to_s.constantize
|
33
51
|
end
|
52
|
+
private :base_class
|
34
53
|
|
35
|
-
alias_method :all, :call
|
36
|
-
|
37
|
-
attr_accessor :default_relation
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: querii
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-03-
|
12
|
+
date: 2017-03-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|