Module: Rokaki::FilterModel
- Includes:
- Filterable
- Defined in:
- lib/rokaki/filter_model.rb,
lib/rokaki/filter_model/join_map.rb,
lib/rokaki/filter_model/like_keys.rb,
lib/rokaki/filter_model/basic_filter.rb,
lib/rokaki/filter_model/filter_chain.rb,
lib/rokaki/filter_model/nested_filter.rb,
lib/rokaki/filter_model/deep_assign_struct.rb,
lib/rokaki/filter_model/nested_like_filters.rb
Defined Under Namespace
Modules: ClassMethods Classes: BasicFilter, DeepAssignStruct, FilterChain, JoinMap, LikeKeys, NestedFilter, NestedLikeFilters
Class Method Summary collapse
Instance Method Summary collapse
-
#escape_like(term) ⇒ Object
Escape special LIKE characters in SQL Server patterns: %, _, [ and \.
-
#generic_like(model, column, type, value, mode) ⇒ Object
Compose a generic LIKE relation supporting arrays of terms (OR chained) Used for adapters without special handling (e.g., SQLite).
-
#oracle_like(model, column, type_signal, value, mode) ⇒ Object
Compose an Oracle LIKE relation supporting arrays of terms and case-insensitive path via UPPER() type_signal: 'LIKE' for case-sensitive semantics; 'ILIKE' to indicate case-insensitive (we will translate).
-
#prepare_like_terms(param, mode) ⇒ Object
Build LIKE patterns with proper prefix/suffix/circumfix and escaping for SQL Server Returns a String when param is scalar, or an Array of Strings when param is an Array.
-
#prepare_or_terms(param, type, mode) ⇒ Object
"SELECT
articles.* FROMarticlesINNER JOINauthorsONauthors.id=articles.author_idWHERE (authors.first_nameLIKE BINARY '%teev%' ORauthors.first_nameLIKE BINARY '%arv%')". - #prepare_regex_terms(param, mode) ⇒ Object
- #prepare_terms(param, mode) ⇒ Object
-
#sqlserver_like(model, column, type, value, mode) ⇒ Object
Compose a SQL Server LIKE relation supporting arrays of terms (OR chained) column should be a fully qualified column expression, e.g., "authors.first_name" or "cs.title" type is usually "LIKE".
Methods included from Filterable
Class Method Details
.included(base) ⇒ Object
6 7 8 |
# File 'lib/rokaki/filter_model.rb', line 6 def self.included(base) base.extend(ClassMethods) end |
Instance Method Details
#escape_like(term) ⇒ Object
Escape special LIKE characters in SQL Server patterns: %, _, [ and \
23 24 25 |
# File 'lib/rokaki/filter_model.rb', line 23 def escape_like(term) term.to_s.gsub(/[\\%_\[]/) { |m| "\\#{m}" } end |
#generic_like(model, column, type, value, mode) ⇒ Object
Compose a generic LIKE relation supporting arrays of terms (OR chained) Used for adapters without special handling (e.g., SQLite)
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rokaki/filter_model.rb', line 95 def generic_like(model, column, type, value, mode) terms = prepare_terms(value, mode) return model.none if terms.nil? if terms.is_a?(Array) return model.none if terms.empty? rel = model.where("#{column} #{type} :q0", q0: terms[0]) terms[1..-1]&.each_with_index do |t, i| rel = rel.or(model.where("#{column} #{type} :q#{i + 1}", "q#{i + 1}".to_sym => t)) end rel else # prepare_terms returns arrays for scalar input, so this branch is rarely used model.where("#{column} #{type} :q", q: terms) end end |
#oracle_like(model, column, type_signal, value, mode) ⇒ Object
Compose an Oracle LIKE relation supporting arrays of terms and case-insensitive path via UPPER() type_signal: 'LIKE' for case-sensitive semantics; 'ILIKE' to indicate case-insensitive (we will translate)
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/rokaki/filter_model.rb', line 74 def oracle_like(model, column, type_signal, value, mode) terms = prepare_like_terms(value, mode) ci = (type_signal.to_s.upcase == 'ILIKE') col_expr = ci ? "UPPER(#{column})" : column build_term = proc { |t| ci ? t.to_s.upcase : t } if terms.is_a?(Array) return model.none if terms.empty? first = build_term.call(terms[0]) rel = model.where("#{col_expr} LIKE :q0 ESCAPE '\\'", q0: first) terms[1..-1]&.each_with_index do |t, i| rel = rel.or(model.where("#{col_expr} LIKE :q#{i + 1} ESCAPE '\\'", "q#{i + 1}".to_sym => build_term.call(t))) end rel else model.where("#{col_expr} LIKE :q ESCAPE '\\'", q: build_term.call(terms)) end end |
#prepare_like_terms(param, mode) ⇒ Object
Build LIKE patterns with proper prefix/suffix/circumfix and escaping for SQL Server Returns a String when param is scalar, or an Array of Strings when param is an Array
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/rokaki/filter_model.rb', line 29 def prepare_like_terms(param, mode) if Array === param case mode when :circumfix param.map { |t| "%#{escape_like(t)}%" } when :prefix param.map { |t| "%#{escape_like(t)}" } when :suffix param.map { |t| "#{escape_like(t)}%" } else param.map { |t| "%#{escape_like(t)}%" } end else case mode when :circumfix "%#{escape_like(param)}%" when :prefix "%#{escape_like(param)}" when :suffix "#{escape_like(param)}%" else "%#{escape_like(param)}%" end end end |
#prepare_or_terms(param, type, mode) ⇒ Object
"SELECT articles.* FROM articles INNER JOIN authors ON authors.id = articles.author_id WHERE (authors.first_name LIKE BINARY '%teev%' OR authors.first_name LIKE BINARY '%arv%')"
125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/rokaki/filter_model.rb', line 125 def prepare_or_terms(param, type, mode) if Array === param param_map = param.map { |term| "%#{term}%" } if mode == :circumfix param_map = param.map { |term| "%#{term}" } if mode == :prefix param_map = param.map { |term| "#{term}%" } if mode == :suffix return param_map.join(" OR #{type} ") else return ["%#{param}%"] if mode == :circumfix return ["%#{param}"] if mode == :prefix return ["#{param}%"] if mode == :suffix end end |
#prepare_regex_terms(param, mode) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/rokaki/filter_model.rb', line 111 def prepare_regex_terms(param, mode) if Array === param param_map = param.map { |term| ".*#{term}.*" } if mode == :circumfix param_map = param.map { |term| ".*#{term}" } if mode == :prefix param_map = param.map { |term| "#{term}.*" } if mode == :suffix return param_map.join("|") else return [".*#{param}.*"] if mode == :circumfix return [".*#{param}"] if mode == :prefix return ["#{param}.*"] if mode == :suffix end end |
#prepare_terms(param, mode) ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/rokaki/filter_model.rb', line 10 def prepare_terms(param, mode) if Array === param return param.map { |term| "%#{term}%" } if mode == :circumfix return param.map { |term| "%#{term}" } if mode == :prefix return param.map { |term| "#{term}%" } if mode == :suffix else return ["%#{param}%"] if mode == :circumfix return ["%#{param}"] if mode == :prefix return ["#{param}%"] if mode == :suffix end end |
#sqlserver_like(model, column, type, value, mode) ⇒ Object
Compose a SQL Server LIKE relation supporting arrays of terms (OR chained) column should be a fully qualified column expression, e.g., "authors.first_name" or "cs.title" type is usually "LIKE"
58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/rokaki/filter_model.rb', line 58 def sqlserver_like(model, column, type, value, mode) terms = prepare_like_terms(value, mode) if terms.is_a?(Array) return model.none if terms.empty? rel = model.where("#{column} #{type} :q0 ESCAPE '\\'", q0: terms[0]) terms[1..-1]&.each_with_index do |t, i| rel = rel.or(model.where("#{column} #{type} :q#{i + 1} ESCAPE '\\'", "q#{i + 1}".to_sym => t)) end rel else model.where("#{column} #{type} :q ESCAPE '\\'", q: terms) end end |