rokaki 0.3.0 → 0.4.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: 1731cab4173cbacc31862d09d6825ee0a6158ec70845bf78dfe3c9ed5cfa1edd
4
- data.tar.gz: c9ff65505f778861b286f94196791bb7a36c79933e8b8136604ea1d9f97579da
3
+ metadata.gz: 0fd44ddd6bbfce39a8417111397fda97131f893d9e502b9a43c1068a18fae5ba
4
+ data.tar.gz: b17ce9c86ae2a7ed95a358662c48fde64e29c6d647a4d3e38f7d13ac6275f201
5
5
  SHA512:
6
- metadata.gz: ee38b03675197b3cc8f9dca7f64e0475ea3c5265163de87e9110b0976f08ab6030a7e4b3a1540050ec8870ec64942af2982e9a688309e1100cc851eb6534aa6d
7
- data.tar.gz: 9eb901aa514cd3efa3731193340033b3fc48a55e2ba76b398ecc289756a912531abda70a3604f2cf5d71d2799b5161ce11283b442267ad73e3cc94ad197df851
6
+ metadata.gz: 8574514a686795b089997a792cbf188ac82ed8751a94d5a0469d6ed92cf7860dd31d13762887972c6546e7e24f5427dfdd52f1c907c95e82de8f4509bec3d616
7
+ data.tar.gz: a38042fff170ed676be0fd9585b2fc9f1ce7ed9691fead44c9744724d6dfe94c65ed8ab005feaaaf7555268f653ab1906aa2765012036698cc8b4a43bb49c0e8
data/README.md CHANGED
@@ -30,6 +30,7 @@ A simple example might be:-
30
30
  @filters = filters
31
31
  @articles = Article
32
32
  end
33
+
33
34
  attr_accessor :filters
34
35
 
35
36
  define_filter_keys :date, author: [:first_name, :last_name]
@@ -84,7 +85,35 @@ filtered_results = filter.results
84
85
  ```
85
86
 
86
87
  ### 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
+ You can use `like` to perform a partial match on a specific key, there are 3 options:- `:prefix`, `:circumfix` and `:suffix`. There are two syntaxes you can use for this:-
89
+
90
+ #### 1. The `filter` command syntax
91
+
92
+
93
+ ```
94
+ class ArticleFilter
95
+ include FilterModel
96
+
97
+ filter :article,
98
+ like: {
99
+ author: {
100
+ first_name: :circumfix,
101
+ last_name: :circumfix
102
+ }
103
+ },
104
+
105
+ attr_accessor :filters
106
+
107
+ def initialize(filters:)
108
+ @filters = filters
109
+ end
110
+ end
111
+ ```
112
+ Or
113
+
114
+ #### 2. The porcelain command syntax
115
+
116
+ In this syntax you will need to provide three keywords:- `filters`, `like` and `filter_model` if you are not passing in the model type and assigning it to `@model`
88
117
 
89
118
 
90
119
  ```
@@ -103,6 +132,24 @@ class ArticleFilter
103
132
  end
104
133
  ```
105
134
 
135
+ Or without the model in the initializer
136
+
137
+ ```
138
+ class ArticleFilter
139
+ include FilterModel
140
+
141
+ filters :date, :title, author: [:first_name, :last_name]
142
+ like title: :circumfix
143
+ filter_model :article
144
+
145
+ attr_accessor :filters
146
+
147
+ def initialize(filters:)
148
+ @filters = filters
149
+ end
150
+ end
151
+ ```
152
+
106
153
  Would produce a query with a LIKE which circumfixes '%' around the filter term, like:-
107
154
 
108
155
  ```
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rokaki
4
+ module FilterModel
5
+ module Like
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def like(args)
12
+ raise ArgumentError, 'argument mush be a hash' unless args.is_a? Hash
13
+ @_like_semantics = (@_like_semantics || {}).merge(args)
14
+ end
15
+
16
+ def _chain_filter_like_type(key)
17
+ filter = "#{filter_key_prefix}#{key}"
18
+
19
+ query = "@model.where(\"#{key} LIKE :query\", "
20
+ if mode == :circumfix
21
+ query += "query: \"%\#{#{filter}}%\")"
22
+ end
23
+ if mode == :infix
24
+ query += "query: \"%\#{#{filter}}\")"
25
+ end
26
+ if mode == :suffix
27
+ query += "query: \"\#{#{filter}}%\")"
28
+ end
29
+ "#{query};"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -12,46 +12,57 @@ module Rokaki
12
12
 
13
13
  private
14
14
 
15
+ def filter(model, options)
16
+ filter_model(model)
17
+
18
+ like(options[:like]) if options[:like]
19
+ filters(*options[:match]) if options[:match]
20
+ end
21
+
15
22
  def filters(*filter_keys)
16
23
  define_filter_keys *filter_keys
17
24
 
18
- @_chain_filters = []
25
+ @_chain_filters ||= []
19
26
  filter_keys.each do |filter_key|
20
- _chain_filter(filter_key) unless filter_key.is_a? Hash
21
- _chain_nested filter_key if filter_key.is_a? Hash
27
+ _chain_filter([filter_key]) unless filter_key.is_a? Hash
28
+ _chain_nested(filter_key) if filter_key.is_a? Hash
22
29
  end
23
30
 
24
31
  define_results
25
32
  end
26
33
 
27
- def _chain_filter(key)
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
34
+ def _chain_filter(keys)
35
+ first_key = keys.shift
36
+ filter = "#{filter_key_prefix}#{first_key}"
37
+ name = first_key
38
+
39
+ keys.each do |key|
40
+ filter += "#{filter_key_infix}#{key}"
41
+ name += "#{filter_key_infix}#{key}"
42
+ end
32
43
 
33
- @_chain_filters << "@model = #{filter_key_prefix}filter_#{key} if #{filter};"
44
+ filter_method = "def #{filter_key_prefix}filter_#{name};" \
45
+ "#{_chain_filter_type(name)} end;"
46
+
47
+ class_eval filter_method, __FILE__, __LINE__ - 2
48
+
49
+ @_chain_filters << "@model = #{filter_key_prefix}filter_#{name} if #{filter};"
34
50
  end
35
51
 
36
52
  def _chain_filter_type(key)
37
53
  filter = "#{filter_key_prefix}#{key}"
38
54
 
39
- query = ""
55
+ query = ''
40
56
  if @_like_semantics && mode = @_like_semantics[key]
41
57
  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
58
+ query += "query: \"%\#{#{filter}}%\")" if mode == :circumfix
59
+ query += "query: \"%\#{#{filter}}\")" if mode == :prefix
60
+ query += "query: \"\#{#{filter}}%\")" if mode == :suffix
51
61
  else
52
62
  query = "@model.where(#{filter}: #{key})"
53
63
  end
54
- "#{query};"
64
+
65
+ query
55
66
  end
56
67
 
57
68
  def _build_deep_chain(keys)
@@ -72,13 +83,15 @@ module Rokaki
72
83
  where = "{ #{key.to_s.pluralize}: { #{leaf}: #{name} } }"
73
84
  end
74
85
 
75
-
76
86
  joins = joins += out
77
87
  where = where += out
78
88
 
79
- class_eval "def #{filter_key_prefix.to_s}filter_#{name};"\
80
- "@model.joins(#{joins}).where(#{where}); end;",
81
- __FILE__, __LINE__ - 2
89
+ # chain filter here?
90
+ #
91
+ filter_method = "def #{filter_key_prefix}filter_#{name};"\
92
+ "@model.joins(#{joins}).where(#{where}); end;"
93
+
94
+ class_eval filter_method, __FILE__, __LINE__ - 2
82
95
 
83
96
  @_chain_filters << "@model = #{filter_key_prefix}filter_#{name} if #{name};"
84
97
  end
@@ -94,12 +107,45 @@ module Rokaki
94
107
  end
95
108
 
96
109
  def filter_model(model)
97
- @model = model
110
+ @model = (model.is_a?(Class) ? model : Object.const_get(model.capitalize))
111
+ class_eval "def model; @model ||= #{@model}; end;"
98
112
  end
99
113
 
100
114
  def like(args)
101
115
  raise ArgumentError, 'argument mush be a hash' unless args.is_a? Hash
116
+
117
+ like_keys = {base: []}
118
+ args.keys.each do |key|
119
+ map_like_keys(like_keys, args, key)
120
+ end
121
+
102
122
  @_like_semantics = (@_like_semantics || {}).merge(args)
123
+
124
+ base_keys = like_keys.delete(:base)
125
+ key_results = base_keys << like_keys
126
+
127
+ filters(*key_results)
128
+ end
129
+
130
+ def map_like_keys(key_result, base_object, key)
131
+ sub_object = base_object[key]
132
+ if sub_object.is_a? Hash
133
+ sub_object.keys.each do |sub_key|
134
+ sub_object_value = sub_object[sub_key]
135
+ if sub_object_value.is_a? Symbol
136
+ if key_result[key].is_a? Array
137
+ key_result[key] << sub_key
138
+ else
139
+ key_result[key] = [sub_key]
140
+ end
141
+ elsif sub_object_value.is_a? Hash
142
+ map_like_keys(key_result, sub_object, sub_key)
143
+ end
144
+ end
145
+ elsif sub_object.is_a? Symbol
146
+ key_result[:base] << key
147
+ end
148
+ key_result
103
149
  end
104
150
 
105
151
  def deep_chain(keys, value)
@@ -123,8 +169,11 @@ module Rokaki
123
169
  end
124
170
  end
125
171
 
172
+ # the model method is called to instatiate @model from the
173
+ # filter_model method
174
+ #
126
175
  def define_results
127
- results_def = 'def results;'
176
+ results_def = 'def results;model;'
128
177
  @_chain_filters.each do |item|
129
178
  results_def += item
130
179
  end
@@ -26,14 +26,11 @@ module Rokaki
26
26
 
27
27
  def _build_filter(keys)
28
28
  name = @filter_key_prefix.to_s
29
- filters = "filters"
30
29
  count = keys.size - 1
31
30
 
32
31
  keys.each_with_index do |key, i|
33
32
  name += key.to_s
34
33
  name += filter_key_infix.to_s unless count == i
35
-
36
- filters += "[:#{key}]"
37
34
  end
38
35
 
39
36
  class_eval "def #{name}; filters.dig(*#{keys}); end;", __FILE__, __LINE__
@@ -53,6 +50,7 @@ module Rokaki
53
50
  end
54
51
  end
55
52
 
53
+
56
54
  if value.is_a? Array
57
55
  value.each do |av|
58
56
  _keys = keys.dup << av
@@ -1,3 +1,3 @@
1
1
  module Rokaki
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.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.3.0
4
+ version: 0.4.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-04 00:00:00.000000000 Z
11
+ date: 2019-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -143,6 +143,7 @@ files:
143
143
  - bin/setup
144
144
  - lib/rokaki.rb
145
145
  - lib/rokaki/filter_model.rb
146
+ - lib/rokaki/filter_model/like.rb
146
147
  - lib/rokaki/filterable.rb
147
148
  - lib/rokaki/version.rb
148
149
  - rokaki.gemspec