Beispiel #1
0
def make_mock_engine(name):
    """
    Creates a mock sqlalchemy engine for testing dialect functionality

    """
    if Version(sa.__version__) >= Version('1.4.0'):
        return sa.create_mock_engine(URL(drivername=name), executor=None)
    else:
        return sa.create_engine(URL(drivername=name, ),
                                strategy='mock',
                                executor=None)
Beispiel #2
0
def print_schema(metadata=_globals.REGISTRY.metadata,
                 *,
                 file=None,
                 engine=_globals.ENGINE):
    """Print the SQL from metadata.create_all() without executing."""
    def print_sql(sql):
        print(sql.compile(dialect=engine.dialect), file=file)

    mock_engine = sa.create_mock_engine(engine.url, executor=print_sql)

    metadata.create_all(mock_engine, checkfirst=False)
    def mock_engine(self):
        def executor(*a, **kw):
            return None

        engine = create_mock_engine(testing.db.name + "://", executor)
        # fmt: off
        engine.dialect.identifier_preparer = \
            tsa.sql.compiler.IdentifierPreparer(
                engine.dialect
            )
        # fmt: on
        return engine
Beispiel #4
0
def get_ddl(*cbs: Callable[[sqlalchemy.engine.Engine], None]) -> str:
    # By default sqlalchemy treats asyncpg as if it had paramstyle="format", which means it tries to escape percent
    # signs. We don't want that so we have to override the paramstyle. Ideally "numeric" would be the right choice here
    # but that doesn't work.
    dialect = sqlalchemy.dialects.postgresql.dialect(
        paramstyle="qmark")  # type: ignore
    ddls = []

    def executor(sql: sqlalchemy.schema.DDLElement) -> None:
        ddls.append(str(sql.compile(dialect=dialect)) + ";")

    mock_engine = sqlalchemy.create_mock_engine("postgresql://", executor)
    for cb in cbs:
        cb(mock_engine)  # type: ignore

    return "\n".join(ddls)
Beispiel #5
0
def dump_model_ddl(dialect: str, metadata: str):
    """

    :param dialect:
    :param metadata:
    """
    dialect = dialect or "sqlite"
    _metadata = import_from_module(metadata)
    engine = create_mock_engine(
        f"{dialect}://",
        executor=lambda sql, *_, **__: print(
            str(sql.compile(dialect=engine.dialect)).replace("\n\n", ";"
                                                             )  # type: ignore
        ),
    )
    _metadata.create_all(engine)
Beispiel #6
0
def create_mock_engine(bind, stream=None):
    """Create a mock SQLAlchemy engine from the passed engine or bind URL.

    :param bind: A SQLAlchemy engine or bind URL to mock.
    :param stream: Render all DDL operations to the stream.
    """

    if not isinstance(bind, six.string_types):
        bind_url = str(bind.url)

    else:
        bind_url = bind

    if stream is not None:

        def dump(sql, *args, **kwargs):
            class Compiler(type(sql._compiler(engine.dialect))):
                def visit_bindparam(self, bindparam, *args, **kwargs):
                    return self.render_literal_value(bindparam.value,
                                                     bindparam.type)

                def render_literal_value(self, value, type_):
                    if isinstance(value, six.integer_types):
                        return str(value)

                    elif isinstance(value, (datetime.date, datetime.datetime)):
                        return "'%s'" % value

                    return super(Compiler,
                                 self).render_literal_value(value, type_)

            text = str(Compiler(engine.dialect, sql).process(sql))
            text = re.sub(r'\n+', '\n', text)
            text = text.strip('\n').strip()

            stream.write('\n%s;' % text)

    else:

        def dump(*args, **kw):
            return None

    try:
        engine = sa.create_mock_engine(bind_url, executor=dump)
    except AttributeError:  # SQLAlchemy <1.4
        engine = sa.create_engine(bind_url, strategy='mock', executor=dump)
    return engine
Beispiel #7
0
def mock_engine(dialect_name=None):
    """Provides a mocking engine based on the current testing.db.

    This is normally used to test DDL generation flow as emitted
    by an Engine.

    It should not be used in other cases, as assert_compile() and
    assert_sql_execution() are much better choices with fewer
    moving parts.

    """

    from sqlalchemy import create_mock_engine

    if not dialect_name:
        dialect_name = config.db.name

    buffer = []

    def executor(sql, *a, **kw):
        buffer.append(sql)

    def assert_sql(stmts):
        recv = [re.sub(r"[\n\t]", "", str(s)) for s in buffer]
        assert recv == stmts, recv

    def print_sql():
        d = engine.dialect
        return "\n".join(str(s.compile(dialect=d)) for s in engine.mock)

    engine = create_mock_engine(dialect_name + "://", executor)
    assert not hasattr(engine, "mock")
    engine.mock = buffer
    engine.assert_sql = assert_sql
    engine.print_sql = print_sql
    return engine