Arel regex match

Cześć,

Potrzebuję użyć konstrukcji Arel dla zapytania match reqexp typu:

"wyszukaj wszystkie elementy, gdzie w kolumnie “moja_kolumna” z “moja_tabela”
zawierające przykładowo takie wartości:

id  moja_kolumna
1   "1.2.3.[11-99,120-124], 1.2.4.[10-29,40-49,101-113]"
2   "2.2.3.[31-39,50-56]" 
3   "2.2.4.[100-120], 1.2.4.[10-29,40-49,200-203]"

po podaniu wartości 52 zostanie wybrany wiersz 1 ([11-99…)
i wiersz 2 (…50-56)

Tak wygląda kod dla zwykłego “match”

    def filter_custom_column_condition
      ->(column, value) { ::Arel::Nodes::SqlLiteral.new(column.field.to_s).matches("#{ column.search.value }%") }
    end

Wdzięczny będę za pomoc

Jeśli dobrze zrozumiałem, to chcesz za pomocą regexa wyciągnąć wszystkie rekordy, które mają przedział obejmujący podaną wartość liczbową? (z tego co widzę to są jakieś filtry na adresy IP, tak?)

Niestety, ale regexem tego nie zrobisz. Wprawdzie da się wygenerować taki regex, który będzie matchować to co opisałeś, ale jest to absolutnie niepraktyczne. Polegałoby to na wygenerowaniu wszystkich możliwych przedziałów X-Y, które mogą zawierać liczbę N (zakładając, 0 <= X <= Y <= 255) i połączeniu ich alternatywą.

Nie pozostaje nic innego jak przefiltrować rekordy na poziome rubiego.

1 Like

image

Dobra, to przypadek inny, prostszy … :slight_smile:
Mam takie rekordy jak na obrazku.
Funkcję mam taką:

  def filter_custom_column_condition
    ->(column, value) { 
      sql_str = "( " + 
        "'#{value}' ~ ('^' || replace(replace(replace(#{column.field.to_s}, '(', '['), ',', ''), ')', ']')  || '[0-9]*$') " +
        " OR scope ILIKE '#{value}%' ) " +
        " AND (length('#{value}') <= 9 ) ";
      ::Arel::Nodes::SqlLiteral.new("#{sql_str}") 
      }
  end

I to działa jako zapytanie SQL. I działa super
Mogę przykładowo wpisać 122128 i wybiera mi trzeci rekord.
…Tylko nie chcę pisać tego jako tekstu SQL (jak powyżej w funkcji) lecz jako wyrażenie Arel …matches
Jak to powinno wyglądać?

Nie znam aż tak dobrze Arela, ale matchowania regexpem jest metoda matches_regexp. Jaki jest w ogóle powód, dla którego chcesz wykonać tę przeróbkę?

Co do tego prostszego przykładu i rozwiązania, które działa. To przytoczone rozwiązanie jest trochę hackiem, chociaż muszę przyznać, że sprytnym. Skoro założyłeś ten wątek to wnioskuję, że nie wiesz jak ono działa. Ono nie ma szans zadziałać z przedziałami dwucyfrowymi typu (10-29) z uwagi na to, że zostanie on zamieniony na klasę znaków [10-29] i wcale nie będzie to łapać wartości z tego przedziału, lecz pojedynczą cyfrę ze zbioru 1,0-2,9 (czyli 0,1,2,9). Nie da się dostosować tego rozwiązania dla dwucyfrowych liczb.

Muszę zmienić, gdyż mając kilka takich funkcji jest zgłaszany błąd, iż nie da łączyć SqlLiteral gdy definiowane są jako text sql

No cóż …
Wygląda na to, że Arel nie jest prosty :slight_smile: