rokaki 0.2.0 → 0.3.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 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