Как я могу сделать REGEXP_REPLACE в SQLAlchemy с SQLite? - PullRequest
0 голосов
/ 06 апреля 2020

У меня есть сайт с поддержкой Postgres, и я использую REGEXP_REPLACE для замены первого экземпляра значения в некоторых столбцах. Это хорошо. Проблема возникает там, где мне нужно запустить CI, и по той или иной причине (ограничения действий Github и виртуальных машин Windows) я не могу использовать Postgres в своих тестах.

Выбор SQLite привел к несколько тестовых сбоев, и я понял, что в SQLite нет встроенного REGEXP_REPLACE.

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such function: regexp_replace
E       [SQL: SELECT job_site.created_at AS job_site_created_at, ..., job_site.neighborhood_id AS job_site_neighborhood_id 
E       FROM job_site 
E       WHERE regexp_replace(job_site.name, ?, ?) = ?]
E       [parameters: (' - ', ':', 'BGS:NEEA - 1894 - 05700 Brown Islands Suite 681')]
E       (Background on this error at: http://sqlalche.me/e/e3q8)

Как я могу добавить эту функцию в SQLite в SQLAlchemy?

1 Ответ

0 голосов
/ 06 апреля 2020

Оказалось, что решением было зарегистрировать regexp_replace как GenericFunction ( docs ) и добавить компилятор c, определяющий диалект ( docs ), используется при работе с движком SQLite.

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.functions import GenericFunction


class regexp_replace(GenericFunction):
    type = String
    identifier = "regexp_replace"


@compiles(regexp_replace, "sqlite")
def visit_regexp_replace(element, compiler, **kw):
    column, pattern, replacement = list(element.clauses)
    return (
        f"SUBSTR({column}, 0, INSTR ({column}, '{pattern.value}')) "
        f"|| '{replacement.value}' "
        f"|| SUBSTR({column}, INSTR ({column}, '{pattern.value}') + LENGTH('{pattern.value}'))"
    )

Также возможно использовать расширение SQLite C, как было предложено здесь , но я не собирался делать эту работу.

...