rokaki 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 732268408b0eaebe95dc53cfd1cb3788c10d198bb47eddb3f4c75d0ff796d98c
4
- data.tar.gz: d698e633dd2d8b48ee086c37e35121c870bc16c40a43070f8c8a5f1db04fc8fd
3
+ metadata.gz: 1731cab4173cbacc31862d09d6825ee0a6158ec70845bf78dfe3c9ed5cfa1edd
4
+ data.tar.gz: c9ff65505f778861b286f94196791bb7a36c79933e8b8136604ea1d9f97579da
5
5
  SHA512:
6
- metadata.gz: f2d9eb53031c10422b3133063792d99f534f4e47ef12fcabe61e52f244d221dae997c437665dada3b7036e017fdd6245f24f54b3507a4ee30dfa0ba976cb8c1e
7
- data.tar.gz: e632c271dfc09265b2717e348b7becf7fdf401c1921e34edc6cdae67b52cfc0eeebe481815bd608695236cdfb0008c7a6c662b93c89bb605d8ca10fa8cfa2f37
6
+ metadata.gz: ee38b03675197b3cc8f9dca7f64e0475ea3c5265163de87e9110b0976f08ab6030a7e4b3a1540050ec8870ec64942af2982e9a688309e1100cc851eb6534aa6d
7
+ data.tar.gz: 9eb901aa514cd3efa3731193340033b3fc48a55e2ba76b398ecc289756a912531abda70a3604f2cf5d71d2799b5161ce11283b442267ad73e3cc94ad197df851
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rokaki (0.1.0)
4
+ rokaki (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -47,9 +47,10 @@ This maps attributes `date`, `author_first_name` and `author_last_name` to a fil
47
47
  You can specify a `filter_key_prefix` and a `filter_key_infix` to change the structure of the accessors.
48
48
 
49
49
  `filter_key_prefix :__` would result in key accessors like `__author_first_name`
50
+
50
51
  `filter_key_infix :__` would result in key accessors like `author__first_name`
51
52
 
52
- ### ActiveRecord
53
+ ## ActiveRecord
53
54
  Include `Rokaki::FilterModel` in any ActiveRecord model (only AR >= 6.0.0 tested so far) you can generate the filter keys and the actual filter lookup code using the `filters` keyword on a model like so:-
54
55
 
55
56
  ```
@@ -80,7 +81,32 @@ filter = ArticleFilter.new(filters: params[:filters])
80
81
 
81
82
  filtered_results = filter.results
82
83
 
83
- * note: This will currently return full text matches (I hope to add partial matching with like and ilike soon)
84
+ ```
85
+
86
+ ### Partial matching
87
+ You can use `like` to perform a partial match on a specific key, there are 3 options:- `:prefix`, `:circumfix` and `:suffix`.
88
+
89
+
90
+ ```
91
+ class ArticleFilter
92
+ include FilterModel
93
+
94
+ filters :date, :title, author: [:first_name, :last_name]
95
+ like title: :circumfix
96
+
97
+ attr_accessor :filters
98
+
99
+ def initialize(filters:, model: Article)
100
+ @filters = filters
101
+ @model = model
102
+ end
103
+ end
104
+ ```
105
+
106
+ Would produce a query with a LIKE which circumfixes '%' around the filter term, like:-
107
+
108
+ ```
109
+ @model = @model.where('title LIKE :query', query: "%#{title}%")
84
110
  ```
85
111
 
86
112
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rokaki
2
4
  module FilterModel
3
5
  include Filterable
@@ -7,6 +9,7 @@ module Rokaki
7
9
 
8
10
  module ClassMethods
9
11
  include Filterable::ClassMethods
12
+
10
13
  private
11
14
 
12
15
  def filters(*filter_keys)
@@ -22,44 +25,62 @@ module Rokaki
22
25
  end
23
26
 
24
27
  def _chain_filter(key)
25
- @_chain_filters << "@model = @model.where(#{key.to_s}: #{key.to_s}) if #{key.to_s};"
28
+ filter = "#{filter_key_prefix}#{key}"
29
+ class_eval "def #{filter_key_prefix}filter_#{key};" \
30
+ "#{_chain_filter_type(key)} end;",
31
+ __FILE__, __LINE__ - 2
32
+
33
+ @_chain_filters << "@model = #{filter_key_prefix}filter_#{key} if #{filter};"
34
+ end
35
+
36
+ def _chain_filter_type(key)
37
+ filter = "#{filter_key_prefix}#{key}"
38
+
39
+ query = ""
40
+ if @_like_semantics && mode = @_like_semantics[key]
41
+ query = "@model.where(\"#{key} LIKE :query\", "
42
+ if mode == :circumfix
43
+ query += "query: \"%\#{#{filter}}%\")"
44
+ end
45
+ if mode == :prefix
46
+ query += "query: \"%\#{#{filter}}\")"
47
+ end
48
+ if mode == :suffix
49
+ query += "query: \"\#{#{filter}}%\")"
50
+ end
51
+ else
52
+ query = "@model.where(#{filter}: #{key})"
53
+ end
54
+ "#{query};"
26
55
  end
27
56
 
28
57
  def _build_deep_chain(keys)
29
- name = @filter_key_prefix.to_s
58
+ name = filter_key_prefix.to_s
30
59
  count = keys.size - 1
31
60
 
32
- joins = ""
33
- where = ""
34
- out = ""
61
+ joins = ''
62
+ where = ''
63
+ out = ''
35
64
 
36
65
  leaf = keys.pop
37
66
 
38
- keys.each_with_index do |key, i|
39
- if keys.length == 1
40
- name = "#{key}#{filter_key_infix.to_s}#{leaf}"
41
- joins = ":#{key}"
67
+ keys.each_with_index do |key, _i|
68
+ next unless keys.length == 1
69
+ name = "#{filter_key_prefix}#{key}#{filter_key_infix}#{leaf}"
70
+ joins = ":#{key}"
42
71
 
43
- where = "{ #{key.to_s.pluralize}: { #{leaf}: #{name} } }"
44
- end
72
+ where = "{ #{key.to_s.pluralize}: { #{leaf}: #{name} } }"
45
73
  end
46
74
 
47
- # keys.each_with_index do |key, i|
48
- # name += key.to_s
49
- # name += filter_key_infix.to_s unless count == i
50
-
51
- # joins += "{ #{key.to_s}: " unless count == i
52
- # where += "{ #{key.to_s.pluralize}: " unless count == i
53
- # out += " }" unless count == i
54
-
55
- # joins += key.to_s if count == i
56
- # where += name if count == i
57
- # end
58
75
 
59
76
  joins = joins += out
60
77
  where = where += out
61
78
 
62
- @_chain_filters << "@model = @model.joins(#{joins}).where(#{where}) if #{name};"
79
+ class_eval "def #{filter_key_prefix.to_s}filter_#{name};"\
80
+ "@model.joins(#{joins}).where(#{where}); end;",
81
+ __FILE__, __LINE__ - 2
82
+
83
+ @_chain_filters << "@model = #{filter_key_prefix}filter_#{name} if #{name};"
63
84
  end
64
85
 
65
86
  def _chain_nested(filters_object)
@@ -76,8 +97,9 @@ module Rokaki
76
97
  @model = model
77
98
  end
78
99
 
79
- def like(*args)
80
-
100
+ def like(args)
101
+ raise ArgumentError, 'argument mush be a hash' unless args.is_a? Hash
102
+ @_like_semantics = (@_like_semantics || {}).merge(args)
81
103
  end
82
104
 
83
105
  def deep_chain(keys, value)
@@ -102,12 +124,12 @@ module Rokaki
102
124
  end
103
125
 
104
126
  def define_results
105
- results_def = "def results;"
127
+ results_def = 'def results;'
106
128
  @_chain_filters.each do |item|
107
129
  results_def += item
108
130
  end
109
131
  results_def += '@model;end;'
110
- class_eval results_def
132
+ class_eval results_def, __FILE__, __LINE__
111
133
  end
112
134
  end
113
135
  end
@@ -16,7 +16,7 @@ module Rokaki
16
16
  end
17
17
  end
18
18
 
19
- def filter_key_prefix(prefix)
19
+ def filter_key_prefix(prefix = nil)
20
20
  @filter_key_prefix ||= prefix
21
21
  end
22
22
 
@@ -1,3 +1,3 @@
1
1
  module Rokaki
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rokaki
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Martin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-09-02 00:00:00.000000000 Z
11
+ date: 2019-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler