paraphrase 0.9.0 → 0.10.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/.travis.yml +4 -1
- data/Appraisals +12 -18
- data/CHANGELOG.md +13 -1
- data/README.md +53 -11
- data/gemfiles/3.1.gemfile +3 -3
- data/gemfiles/3.1.gemfile.lock +47 -42
- data/gemfiles/3.2.gemfile +3 -3
- data/gemfiles/3.2.gemfile.lock +36 -32
- data/gemfiles/4.0.gemfile +3 -3
- data/gemfiles/4.0.gemfile.lock +38 -36
- data/gemfiles/4.1.gemfile +3 -3
- data/gemfiles/4.1.gemfile.lock +35 -31
- data/lib/paraphrase.rb +14 -3
- data/lib/paraphrase/active_model.rb +1 -0
- data/lib/paraphrase/mapping.rb +28 -0
- data/lib/paraphrase/{params.rb → params_filter.rb} +10 -4
- data/lib/paraphrase/query.rb +64 -41
- data/lib/paraphrase/rails.rb +2 -0
- data/lib/paraphrase/repository.rb +36 -0
- data/lib/paraphrase/syntax.rb +12 -2
- data/lib/paraphrase/version.rb +1 -1
- data/paraphrase.gemspec +5 -5
- data/spec/paraphrase/query_spec.rb +39 -10
- data/spec/paraphrase/syntax_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -8
- metadata +15 -19
- data/gemfiles/3.0.gemfile +0 -9
- data/gemfiles/3.0.gemfile.lock +0 -100
- data/lib/paraphrase/errors.rb +0 -3
- data/lib/paraphrase/scope.rb +0 -56
- data/spec/paraphrase/scope_spec.rb +0 -51
data/gemfiles/4.0.gemfile
CHANGED
data/gemfiles/4.0.gemfile.lock
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
PATH
|
2
|
-
remote:
|
2
|
+
remote: ../
|
3
3
|
specs:
|
4
|
-
paraphrase (0.
|
5
|
-
activemodel (>= 3.
|
6
|
-
activerecord (>= 3.
|
7
|
-
activesupport (>= 3.
|
4
|
+
paraphrase (0.10.0)
|
5
|
+
activemodel (>= 3.1, < 4.2)
|
6
|
+
activerecord (>= 3.1, < 4.2)
|
7
|
+
activesupport (>= 3.1, < 4.2)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
actionpack (4.0.
|
13
|
-
activesupport (= 4.0.
|
12
|
+
actionpack (4.0.4)
|
13
|
+
activesupport (= 4.0.4)
|
14
14
|
builder (~> 3.1.0)
|
15
15
|
erubis (~> 2.7.0)
|
16
16
|
rack (~> 1.5.2)
|
17
17
|
rack-test (~> 0.6.2)
|
18
|
-
activemodel (4.0.
|
19
|
-
activesupport (= 4.0.
|
18
|
+
activemodel (4.0.4)
|
19
|
+
activesupport (= 4.0.4)
|
20
20
|
builder (~> 3.1.0)
|
21
|
-
activerecord (4.0.
|
22
|
-
activemodel (= 4.0.
|
21
|
+
activerecord (4.0.4)
|
22
|
+
activemodel (= 4.0.4)
|
23
23
|
activerecord-deprecated_finders (~> 1.0.2)
|
24
|
-
activesupport (= 4.0.
|
24
|
+
activesupport (= 4.0.4)
|
25
25
|
arel (~> 4.0.0)
|
26
26
|
activerecord-deprecated_finders (1.0.3)
|
27
|
-
activesupport (4.0.
|
28
|
-
i18n (~> 0.6, >= 0.6.
|
27
|
+
activesupport (4.0.4)
|
28
|
+
i18n (~> 0.6, >= 0.6.9)
|
29
29
|
minitest (~> 4.2)
|
30
30
|
multi_json (~> 1.3)
|
31
31
|
thread_safe (~> 0.1)
|
@@ -33,8 +33,7 @@ GEM
|
|
33
33
|
appraisal (0.5.2)
|
34
34
|
bundler
|
35
35
|
rake
|
36
|
-
arel (4.0.
|
37
|
-
atomic (1.1.14)
|
36
|
+
arel (4.0.2)
|
38
37
|
builder (3.1.4)
|
39
38
|
codeclimate-test-reporter (0.3.0)
|
40
39
|
simplecov (>= 0.7.1, < 1.0.0)
|
@@ -45,8 +44,8 @@ GEM
|
|
45
44
|
i18n (0.6.9)
|
46
45
|
method_source (0.8.2)
|
47
46
|
minitest (4.7.5)
|
48
|
-
multi_json (1.
|
49
|
-
pry (0.9.12.
|
47
|
+
multi_json (1.10.1)
|
48
|
+
pry (0.9.12.6)
|
50
49
|
coderay (~> 1.0)
|
51
50
|
method_source (~> 0.8)
|
52
51
|
slop (~> 3.4)
|
@@ -55,33 +54,36 @@ GEM
|
|
55
54
|
rack (>= 1.0)
|
56
55
|
rake (0.9.6)
|
57
56
|
redcarpet (2.1.1)
|
58
|
-
rspec (
|
59
|
-
rspec-core (~>
|
60
|
-
rspec-expectations (~>
|
61
|
-
rspec-mocks (~>
|
62
|
-
rspec-core (
|
63
|
-
|
64
|
-
|
65
|
-
|
57
|
+
rspec (3.0.0)
|
58
|
+
rspec-core (~> 3.0.0)
|
59
|
+
rspec-expectations (~> 3.0.0)
|
60
|
+
rspec-mocks (~> 3.0.0)
|
61
|
+
rspec-core (3.0.0)
|
62
|
+
rspec-support (~> 3.0.0)
|
63
|
+
rspec-expectations (3.0.0)
|
64
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
65
|
+
rspec-support (~> 3.0.0)
|
66
|
+
rspec-mocks (3.0.0)
|
67
|
+
rspec-support (~> 3.0.0)
|
68
|
+
rspec-support (3.0.0)
|
66
69
|
simplecov (0.8.2)
|
67
70
|
docile (~> 1.1.0)
|
68
71
|
multi_json
|
69
72
|
simplecov-html (~> 0.8.0)
|
70
73
|
simplecov-html (0.8.0)
|
71
|
-
slop (3.
|
72
|
-
sqlite3 (1.3.
|
73
|
-
thread_safe (0.
|
74
|
-
|
75
|
-
|
76
|
-
yard (0.8.7.3)
|
74
|
+
slop (3.5.0)
|
75
|
+
sqlite3 (1.3.9)
|
76
|
+
thread_safe (0.3.3)
|
77
|
+
tzinfo (0.3.39)
|
78
|
+
yard (0.8.7.4)
|
77
79
|
|
78
80
|
PLATFORMS
|
79
81
|
ruby
|
80
82
|
|
81
83
|
DEPENDENCIES
|
82
|
-
actionpack (~> 4.0)
|
83
|
-
activerecord (~> 4.0)
|
84
|
-
activesupport (~> 4.0)
|
84
|
+
actionpack (~> 4.0.0)
|
85
|
+
activerecord (~> 4.0.0)
|
86
|
+
activesupport (~> 4.0.0)
|
85
87
|
appraisal (~> 0.4)
|
86
88
|
bundler (~> 1.0)
|
87
89
|
codeclimate-test-reporter (~> 0.3)
|
@@ -89,6 +91,6 @@ DEPENDENCIES
|
|
89
91
|
pry (~> 0.9)
|
90
92
|
rake (~> 0.9.2)
|
91
93
|
redcarpet (~> 2.1.1)
|
92
|
-
rspec (~>
|
94
|
+
rspec (~> 3.0)
|
93
95
|
sqlite3 (~> 1.3.6)
|
94
96
|
yard (~> 0.7)
|
data/gemfiles/4.1.gemfile
CHANGED
data/gemfiles/4.1.gemfile.lock
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../
|
3
3
|
specs:
|
4
|
-
paraphrase (0.
|
5
|
-
activemodel (>= 3.
|
6
|
-
activerecord (>= 3.
|
7
|
-
activesupport (>= 3.
|
4
|
+
paraphrase (0.10.0)
|
5
|
+
activemodel (>= 3.1, < 4.2)
|
6
|
+
activerecord (>= 3.1, < 4.2)
|
7
|
+
activesupport (>= 3.1, < 4.2)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
actionpack (4.1.
|
13
|
-
actionview (= 4.1.
|
14
|
-
activesupport (= 4.1.
|
12
|
+
actionpack (4.1.1)
|
13
|
+
actionview (= 4.1.1)
|
14
|
+
activesupport (= 4.1.1)
|
15
15
|
rack (~> 1.5.2)
|
16
16
|
rack-test (~> 0.6.2)
|
17
|
-
actionview (4.1.
|
18
|
-
activesupport (= 4.1.
|
17
|
+
actionview (4.1.1)
|
18
|
+
activesupport (= 4.1.1)
|
19
19
|
builder (~> 3.1)
|
20
20
|
erubis (~> 2.7.0)
|
21
|
-
activemodel (4.1.
|
22
|
-
activesupport (= 4.1.
|
21
|
+
activemodel (4.1.1)
|
22
|
+
activesupport (= 4.1.1)
|
23
23
|
builder (~> 3.1)
|
24
|
-
activerecord (4.1.
|
25
|
-
activemodel (= 4.1.
|
26
|
-
activesupport (= 4.1.
|
24
|
+
activerecord (4.1.1)
|
25
|
+
activemodel (= 4.1.1)
|
26
|
+
activesupport (= 4.1.1)
|
27
27
|
arel (~> 5.0.0)
|
28
|
-
activesupport (4.1.
|
28
|
+
activesupport (4.1.1)
|
29
29
|
i18n (~> 0.6, >= 0.6.9)
|
30
30
|
json (~> 1.7, >= 1.7.7)
|
31
31
|
minitest (~> 5.1)
|
@@ -45,8 +45,8 @@ GEM
|
|
45
45
|
i18n (0.6.9)
|
46
46
|
json (1.8.1)
|
47
47
|
method_source (0.8.2)
|
48
|
-
minitest (5.3.
|
49
|
-
multi_json (1.
|
48
|
+
minitest (5.3.4)
|
49
|
+
multi_json (1.10.1)
|
50
50
|
pry (0.9.12.6)
|
51
51
|
coderay (~> 1.0)
|
52
52
|
method_source (~> 0.8)
|
@@ -56,33 +56,37 @@ GEM
|
|
56
56
|
rack (>= 1.0)
|
57
57
|
rake (0.9.6)
|
58
58
|
redcarpet (2.1.1)
|
59
|
-
rspec (
|
60
|
-
rspec-core (~>
|
61
|
-
rspec-expectations (~>
|
62
|
-
rspec-mocks (~>
|
63
|
-
rspec-core (
|
64
|
-
|
65
|
-
|
66
|
-
|
59
|
+
rspec (3.0.0)
|
60
|
+
rspec-core (~> 3.0.0)
|
61
|
+
rspec-expectations (~> 3.0.0)
|
62
|
+
rspec-mocks (~> 3.0.0)
|
63
|
+
rspec-core (3.0.0)
|
64
|
+
rspec-support (~> 3.0.0)
|
65
|
+
rspec-expectations (3.0.0)
|
66
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
67
|
+
rspec-support (~> 3.0.0)
|
68
|
+
rspec-mocks (3.0.0)
|
69
|
+
rspec-support (~> 3.0.0)
|
70
|
+
rspec-support (3.0.0)
|
67
71
|
simplecov (0.8.2)
|
68
72
|
docile (~> 1.1.0)
|
69
73
|
multi_json
|
70
74
|
simplecov-html (~> 0.8.0)
|
71
75
|
simplecov-html (0.8.0)
|
72
76
|
slop (3.5.0)
|
73
|
-
sqlite3 (1.3.
|
77
|
+
sqlite3 (1.3.9)
|
74
78
|
thread_safe (0.3.3)
|
75
79
|
tzinfo (1.1.0)
|
76
80
|
thread_safe (~> 0.1)
|
77
|
-
yard (0.8.7.
|
81
|
+
yard (0.8.7.4)
|
78
82
|
|
79
83
|
PLATFORMS
|
80
84
|
ruby
|
81
85
|
|
82
86
|
DEPENDENCIES
|
83
|
-
actionpack (~> 4.1)
|
84
|
-
activerecord (~> 4.1)
|
85
|
-
activesupport (~> 4.1)
|
87
|
+
actionpack (~> 4.1.0)
|
88
|
+
activerecord (~> 4.1.0)
|
89
|
+
activesupport (~> 4.1.0)
|
86
90
|
appraisal (~> 0.4)
|
87
91
|
bundler (~> 1.0)
|
88
92
|
codeclimate-test-reporter (~> 0.3)
|
@@ -90,6 +94,6 @@ DEPENDENCIES
|
|
90
94
|
pry (~> 0.9)
|
91
95
|
rake (~> 0.9.2)
|
92
96
|
redcarpet (~> 2.1.1)
|
93
|
-
rspec (~>
|
97
|
+
rspec (~> 3.0)
|
94
98
|
sqlite3 (~> 1.3.6)
|
95
99
|
yard (~> 0.7)
|
data/lib/paraphrase.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
|
-
|
1
|
+
module Paraphrase
|
2
|
+
class DuplicateMappingError < StandardError
|
3
|
+
def initialize(scope_name)
|
4
|
+
@message = "scope :#{scope_name} has already been mapped"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class NoQueryDefined < StandardError
|
9
|
+
def initialize(query_name)
|
10
|
+
@message = "No query class found. #{query_name} must be defined as a subclass of `Paraphrase::Query`"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
2
15
|
require 'paraphrase/query'
|
3
|
-
require 'paraphrase/scope'
|
4
|
-
require 'paraphrase/syntax'
|
5
16
|
require 'paraphrase/rails' if defined?(Rails)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
require 'active_support/core_ext/array/wrap'
|
3
|
+
|
4
|
+
module Paraphrase
|
5
|
+
# @api private
|
6
|
+
class Mapping
|
7
|
+
attr_reader :keys, :name, :required_keys
|
8
|
+
|
9
|
+
def initialize(keys, options)
|
10
|
+
@keys = keys
|
11
|
+
@name = options[:to]
|
12
|
+
|
13
|
+
@required_keys = if options[:whitelist] == true
|
14
|
+
[]
|
15
|
+
else
|
16
|
+
@keys - Array.wrap(options[:whitelist])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def satisfied?(params)
|
21
|
+
required_keys.all? { |key| params[key] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def values(params)
|
25
|
+
keys.map { |key| params[key] }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,12 +1,18 @@
|
|
1
1
|
module Paraphrase
|
2
|
-
class
|
2
|
+
class ParamsFilter
|
3
3
|
attr_reader :params, :result
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
@params =
|
5
|
+
def initialize(unfiltered_params, keys)
|
6
|
+
@params = unfiltered_params.with_indifferent_access.slice(*keys)
|
7
7
|
|
8
8
|
@result = @params.inject(HashWithIndifferentAccess.new) do |result, (key, value)|
|
9
|
-
value =
|
9
|
+
value = @params[key]
|
10
|
+
|
11
|
+
if respond_to?(key)
|
12
|
+
value = send(key)
|
13
|
+
end
|
14
|
+
|
15
|
+
value = scrub(value)
|
10
16
|
|
11
17
|
if value.present?
|
12
18
|
result[key] = value
|
data/lib/paraphrase/query.rb
CHANGED
@@ -4,92 +4,115 @@ require 'active_support/core_ext/module/delegation'
|
|
4
4
|
require 'active_support/core_ext/string/inflections'
|
5
5
|
require 'active_support/core_ext/array/extract_options'
|
6
6
|
require 'active_support/hash_with_indifferent_access'
|
7
|
+
|
7
8
|
require 'paraphrase/active_model'
|
8
|
-
require 'paraphrase/
|
9
|
+
require 'paraphrase/mapping'
|
10
|
+
require 'paraphrase/params_filter'
|
11
|
+
require 'paraphrase/repository'
|
9
12
|
|
10
13
|
module Paraphrase
|
11
14
|
class Query
|
12
15
|
include ActiveModel
|
13
|
-
# @!attribute [r]
|
14
|
-
# @return [Array<
|
15
|
-
|
16
|
+
# @!attribute [r] mappings
|
17
|
+
# @return [Array<Paraphrase::Mapping>] mappings for query
|
18
|
+
# @!attribute [r] source
|
19
|
+
# @return [Symbol, String] name of the class to use as the source for the
|
20
|
+
# query
|
21
|
+
class_attribute :mappings, instance_writer: false
|
22
|
+
class_attribute :source, instance_writer: false, instance_reader: false
|
23
|
+
class_attribute :params_filter, instance_writer: false
|
24
|
+
class_attribute :repository, instance_writer: false
|
16
25
|
|
17
26
|
# @!attribute [r] params
|
18
|
-
# @return [HashWithIndifferentAccess] filtered parameters based on keys defined in
|
27
|
+
# @return [HashWithIndifferentAccess] filtered parameters based on keys defined in `mappings`
|
19
28
|
#
|
20
29
|
# @!attribute [r] result
|
21
30
|
# @return [ActiveRecord::Relation]
|
22
31
|
attr_reader :params, :result
|
23
32
|
|
24
|
-
# Set `
|
33
|
+
# Set `mappings` on inheritance to ensure they're unique per subclass
|
25
34
|
def self.inherited(klass)
|
26
|
-
klass.
|
27
|
-
|
35
|
+
klass.mappings = []
|
36
|
+
klass.source = klass.to_s.sub(/Query$/, '')
|
28
37
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
self._source = name.to_s
|
38
|
+
klass.params_filter = Class.new(Paraphrase::ParamsFilter)
|
39
|
+
klass.const_set(:ParamsFilter, klass.params_filter)
|
40
|
+
|
41
|
+
klass.repository = Class.new(Paraphrase::Repository)
|
42
|
+
klass.const_set(:Repository, klass.repository)
|
35
43
|
end
|
36
44
|
|
37
45
|
# Keys being mapped to scopes
|
38
46
|
#
|
39
47
|
# @return [Array<Symbol>]
|
40
48
|
def self.keys
|
41
|
-
|
49
|
+
mappings.flat_map(&:keys)
|
42
50
|
end
|
43
51
|
|
44
|
-
#
|
45
|
-
|
46
|
-
self::Params
|
47
|
-
rescue NameError
|
48
|
-
Paraphrase::Params
|
49
|
-
end
|
50
|
-
|
51
|
-
# Add a {Scope} instance to {Query#scopes}. Defines a reader for each key
|
52
|
-
# to read from {Query#params}.
|
52
|
+
# Add a {Mapping} instance to {Query#mappings}. Defines a reader for each
|
53
|
+
# key to read from {Query#params}.
|
53
54
|
#
|
54
|
-
# @
|
55
|
+
# @overload map(*keys, options)
|
56
|
+
# Maps a key to a scope
|
57
|
+
# @param [Array<Symbol>] keys query params to be mapped to the scope
|
58
|
+
# @param [Hash] options options to configure {Mapping Mapping} instance
|
59
|
+
# @option options [Symbol, Array<Symbol>] :to scope to map query params to
|
60
|
+
# @option options [true, Symbol, Array<Symbol>] :whitelist lists all or a
|
61
|
+
# subset of param keys as optional
|
55
62
|
def self.map(*keys)
|
56
63
|
options = keys.extract_options!
|
57
64
|
scope_name = options[:to]
|
58
65
|
|
59
|
-
if
|
60
|
-
raise
|
66
|
+
if mappings.any? { |mapping| mapping.name == scope_name }
|
67
|
+
raise DuplicateMappingError.new(scope_name)
|
61
68
|
end
|
62
69
|
|
63
|
-
|
70
|
+
mappings << Mapping.new(keys, options)
|
64
71
|
|
65
72
|
keys.each do |key|
|
66
73
|
define_method(key) { params[key] }
|
67
74
|
end
|
68
75
|
end
|
69
76
|
|
77
|
+
# Define a method on `ParamsFilter` to process the raw value of the query
|
78
|
+
# param
|
79
|
+
#
|
80
|
+
# @param [Symbol] query_param query param to process
|
81
|
+
# @param [Proc] block block to process the query param
|
82
|
+
def self.param(query_param, &block)
|
83
|
+
params_filter.class_eval do
|
84
|
+
define_method(query_param, &block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Define a scope on `Repository`
|
89
|
+
def self.scope(scope_name, &block)
|
90
|
+
repository.class_eval do
|
91
|
+
define_method(scope_name, &block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
70
95
|
# Filters out parameters irrelevant to the query and sets the base scope
|
71
96
|
# for to begin the chain.
|
72
97
|
#
|
73
98
|
# @param [Hash] params query parameters
|
74
99
|
# @param [ActiveRecord::Relation] relation object to apply methods to
|
75
|
-
def initialize(
|
76
|
-
@params =
|
100
|
+
def initialize(query_params, relation = nil)
|
101
|
+
@params = filter_params(query_params || {})
|
77
102
|
|
78
|
-
@result =
|
79
|
-
|
103
|
+
@result = mappings.inject(relation || default_relation) do |result, mapping|
|
104
|
+
repository.chain(result, mapping, @params)
|
80
105
|
end
|
81
106
|
end
|
82
107
|
|
83
108
|
# Return an `ActiveRecord::Relation` corresponding to the source class
|
84
|
-
# determined from the `
|
85
|
-
# class.
|
109
|
+
# determined from the `source` class attribute that defaults to the name of
|
110
|
+
# the class.
|
86
111
|
#
|
87
112
|
# @return [ActiveRecord::Relation]
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
name.constantize
|
92
|
-
end
|
113
|
+
def default_relation
|
114
|
+
klass = self.class.source.to_s.constantize
|
115
|
+
klass.default_paraphrase_relation
|
93
116
|
end
|
94
117
|
|
95
118
|
# @see Query.keys
|
@@ -99,8 +122,8 @@ module Paraphrase
|
|
99
122
|
|
100
123
|
private
|
101
124
|
|
102
|
-
def
|
103
|
-
|
125
|
+
def filter_params(params)
|
126
|
+
params_filter.new(params, keys).result
|
104
127
|
end
|
105
128
|
end
|
106
129
|
end
|