Цитирование имен таблиц и столбцов в SQLAlchemy - PullRequest
0 голосов
/ 25 апреля 2019

У меня есть функция, которая добавляет триггеры в указанные таблицы, используя этот код ( полный код функции здесь ):

event.listen(primary_table, 'after_create', DDL('''
    CREATE FUNCTION {primary_table_name}_validate() RETURNS TRIGGER AS $$
    DECLARE
        target RECORD;
    BEGIN
        IF (NEW.{rhs} IS NOT NULL) THEN
            SELECT {parentcol} INTO target FROM {child_table_name} WHERE {child_id_column} = NEW.{rhs};
            IF (target.{parentcol} != NEW.{lhs}) THEN
                RAISE foreign_key_violation USING MESSAGE = 'The target is not affiliated with this parent';
            END IF;
        END IF;
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    CREATE TRIGGER {primary_table_name}_trigger BEFORE INSERT OR UPDATE
    ON {primary_table_name}
    FOR EACH ROW EXECUTE PROCEDURE {primary_table_name}_validate();
    '''.format(
    primary_table_name=primary_table_name,
    parentcol=parentcol,
    child_table_name=child_table_name,
    child_id_column=child_id_columns[0],
    lhs=parent_table_name + '_' + parent_id_columns[0],
    rhs=child_table_name + '_' + child_id_columns[0],
)).execute_if(dialect='postgresql'))

event.listen(primary_table, 'before_drop', DDL('''
    DROP TRIGGER {primary_table_name}_trigger ON {primary_table_name};
    DROP FUNCTION {primary_table_name}_validate();
    '''.format(primary_table_name=primary_table_name)).execute_if(dialect='postgresql'))

Я не хочу встраивать необработанные строки вSQL, так как он захлебнется именами типа user (с PostgreSQL).Я не могу использовать SQLAlchemy bindparam, так как это имена таблиц и столбцов, а не данные. SQLAlchemy предлагает quoted_name и quote_identifier, которые, кажется, делают то, что мне нужно, но как их использовать здесь?

1 Ответ

0 голосов
/ 25 апреля 2019

Чтобы ответить на мой собственный вопрос, DDL принимает словарь context, который применяется к оператору SQL.Это исправленный код:

event.listen(primary_table, 'after_create',
    DDL('''
        CREATE FUNCTION %(function)s() RETURNS TRIGGER AS $$
        DECLARE
            target RECORD;
        BEGIN
            IF (NEW.%(rhs)s IS NOT NULL) THEN
                SELECT %(parentcol)s INTO target FROM %(child_table_name)s WHERE %(child_id_column)s = NEW.%(rhs)s;
                IF (target.%(parentcol)s != NEW.%(lhs)s) THEN
                    RAISE foreign_key_violation USING MESSAGE = 'The target is not affiliated with this parent';
                END IF;
            END IF;
            RETURN NEW;
        END;
        $$ LANGUAGE plpgsql;
        CREATE TRIGGER %(trigger)s BEFORE INSERT OR UPDATE
        ON %(table)s
        FOR EACH ROW EXECUTE PROCEDURE %(function)s();
        ''',
        context={
            'table': primary_table_name,
            'function': '%s_validate' % primary_table_name,
            'trigger': '%s_trigger' % primary_table_name,
            'parentcol': parentcol,
            'child_table_name': child_table_name,
            'child_id_column': child_id_columns[0],
            'lhs': '%s_%s' % (parent_table_name, parent_id_columns[0]),
            'rhs': '%s_%s' % (child_table_name, child_id_columns[0]),
        }
    ).execute_if(dialect='postgresql')
)

event.listen(primary_table, 'before_drop',
    DDL('''
        DROP TRIGGER %(trigger)s ON %(table)s;
        DROP FUNCTION %(function)s();
        ''',
        context={
            'table': primary_table_name,
            'trigger': '%s_trigger' % primary_table_name,
            'function': '%s_validate' % primary_table_name,
        }
    ).execute_if(dialect='postgresql')
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...