Module: QueryStream::FilterEngine
- Defined in:
- lib/query_stream/filter_engine.rb
Overview
フィルタリング&ソートエンジンモジュール
Class Method Summary collapse
-
.apply_filters(records, filters) ⇒ Array<Hash>
フィルタ条件をレコード群に適用する.
-
.apply_sort(records, sort) ⇒ Array<Hash>
ソート条件を適用する.
-
.evaluate_filter(record, filter) ⇒ Boolean
単一フィルタ条件をレコードに対して評価する.
-
.evaluate_primary_key_lookup(record, query_value) ⇒ Boolean
主キー候補フィールドを順番に走査して一致するものを探す.
-
.match_eq(field_value, filter_values) ⇒ Object
等値比較(配列・カンマ区切り文字列を透過的に扱う) データ側が配列/カンマ区切りの場合、ORの値リストと交差判定する.
-
.normalize_to_list(value) ⇒ Object
フィールド値をリスト化する(配列/カンマ区切り/単値を統一).
-
.to_comparable(value) ⇒ Object
比較用に値を正規化する(数値変換・日付変換を試みる).
Class Method Details
.apply_filters(records, filters) ⇒ Array<Hash>
フィルタ条件をレコード群に適用する
22 23 24 25 26 27 28 |
# File 'lib/query_stream/filter_engine.rb', line 22 def apply_filters(records, filters) return records if filters.nil? || filters.empty? records.select do |record| filters.all? { evaluate_filter(record, it) } end end |
.apply_sort(records, sort) ⇒ Array<Hash>
ソート条件を適用する
34 35 36 37 |
# File 'lib/query_stream/filter_engine.rb', line 34 def apply_sort(records, sort) sorted = records.sort_by { to_comparable(it[sort[:field]]) } sort[:direction] == :desc ? sorted.reverse : sorted end |
.evaluate_filter(record, filter) ⇒ Boolean
単一フィルタ条件をレコードに対して評価する
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/query_stream/filter_engine.rb', line 43 def evaluate_filter(record, filter) # 主キー検索(_primary_key)の特別処理 if filter[:field] == :_primary_key return evaluate_primary_key_lookup(record, filter[:value]) end field_value = record[filter[:field]] case filter[:op] when :eq match_eq(field_value, filter[:value]) when :neq !match_eq(field_value, filter[:value]) when :gt to_comparable(field_value) > to_comparable(filter[:value]) when :gte to_comparable(field_value) >= to_comparable(filter[:value]) when :lt to_comparable(field_value) < to_comparable(filter[:value]) when :lte to_comparable(field_value) <= to_comparable(filter[:value]) when :range range = filter[:value] range.cover?(to_comparable(field_value)) else false end end |
.evaluate_primary_key_lookup(record, query_value) ⇒ Boolean
主キー候補フィールドを順番に走査して一致するものを探す
76 77 78 79 80 |
# File 'lib/query_stream/filter_engine.rb', line 76 def evaluate_primary_key_lookup(record, query_value) QueryStreamParser::PRIMARY_KEY_FIELDS.any? do |key| record[key]&.to_s == query_value.to_s end end |
.match_eq(field_value, filter_values) ⇒ Object
等値比較(配列・カンマ区切り文字列を透過的に扱う)データ側が配列/カンマ区切りの場合、ORの値リストと交差判定する
84 85 86 87 88 89 90 |
# File 'lib/query_stream/filter_engine.rb', line 84 def match_eq(field_value, filter_values) field_list = normalize_to_list(field_value) value_list = Array(filter_values).map { it.to_s.strip } # フィールド側の値リストと条件値リストに交差があれば一致 (field_list & value_list).any? end |
.normalize_to_list(value) ⇒ Object
フィールド値をリスト化する(配列/カンマ区切り/単値を統一)
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/query_stream/filter_engine.rb', line 93 def normalize_to_list(value) case value when Array value.map { it.to_s.strip } when String value.split(',').map { it.strip } when nil [] else [value.to_s.strip] end end |
.to_comparable(value) ⇒ Object
比較用に値を正規化する(数値変換・日付変換を試みる)
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/query_stream/filter_engine.rb', line 107 def to_comparable(value) case value when Date, Time value when String # 日付形式(YYYY-MM-DD)を検出して Date に変換 if value.match?(/\A\d{4}-\d{2}-\d{2}\z/) begin return Date.parse(value) rescue Date::Error raise InvalidDateError, "無効な日付: #{value}" end end # 数値変換を試みる case value when /\A-?\d+\z/ value.to_i when /\A-?\d+\.\d+\z/ value.to_f else value end when Integer, Float value else value.to_s end end |