Skip to content

Commit 1913c47

Browse files
antdkingTyler Hargraves
authored and
Tyler Hargraves
committed
feat(sqla-core): Add support for rendering Database Specific queries (aws#291)
* chore(sqla_core): setup an area to run postgres tests * fix: run a supported version of postgres in travis by default it runs 9.4. We need to use a feature added in 9.5 * feat(sqla-core): Add support for rendering Database Specific queries This makes the sqla-core plugin aware of how to compile a database specific query. It seems in some cases, we see strings come through (mostly pragma calls when doing 'create_all'), so do a check to see if the object looks like a SQL Expression object. Fixes: aws#290 * fix: remove a spurious 'self' in the fixtures * chore: make the DB URL injectable this reduces duplication of the Engine fixture.
1 parent 80a3cf3 commit 1913c47

File tree

6 files changed

+75
-5
lines changed

6 files changed

+75
-5
lines changed

.travis.yml

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ python:
99
- "3.8"
1010
- "3.9"
1111

12+
addons:
13+
postgresql: "9.6"
14+
1215
install:
1316
- pip install tox tox-travis
1417

aws_xray_sdk/ext/sqlalchemy_core/patch.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
from aws_xray_sdk.core.utils import stacktrace
1414
from aws_xray_sdk.ext.util import unwrap
1515

16+
from sqlalchemy.sql.expression import ClauseElement
17+
1618

1719
def _sql_meta(engine_instance, args):
1820
try:
@@ -41,7 +43,10 @@ def _sql_meta(engine_instance, args):
4143
metadata['database_version'] = '.'.join(map(str, engine_instance.dialect.server_version_info))
4244
if xray_recorder.stream_sql:
4345
try:
44-
metadata['sanitized_query'] = str(args[0])
46+
if isinstance(args[0], ClauseElement):
47+
metadata['sanitized_query'] = str(args[0].compile(engine_instance.engine))
48+
else:
49+
metadata['sanitized_query'] = str(args[0])
4550
except Exception:
4651
logging.getLogger(__name__).exception('Error getting the sanitized query')
4752
except Exception:

tests/ext/sqlalchemy_core/test_base.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@ class User(Base):
2121

2222

2323
@pytest.fixture()
24-
def engine():
24+
def db_url():
25+
return 'sqlite:///:memory:'
26+
27+
28+
@pytest.fixture()
29+
def engine(db_url):
2530
"""
2631
Clean up context storage on each test run and begin a segment
2732
so that later subsegment can be attached. After each test run
2833
it cleans up context storage again.
2934
"""
3035
from aws_xray_sdk.ext.sqlalchemy_core import unpatch
3136
patch(('sqlalchemy_core',))
32-
engine = create_engine('sqlite:///:memory:')
37+
engine = create_engine(db_url)
3338
xray_recorder.configure(service='test', sampling=False, context=Context())
3439
xray_recorder.begin_segment('name')
3540
Base.metadata.create_all(engine)
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import pytest
2+
3+
from .test_base import connection, engine, session, User
4+
5+
from sqlalchemy import create_engine
6+
from sqlalchemy.dialects.postgresql import insert as pg_insert
7+
8+
from aws_xray_sdk.core import xray_recorder, patch
9+
from aws_xray_sdk.core.context import Context
10+
11+
import testing.postgresql
12+
13+
14+
@pytest.fixture()
15+
def postgres_db():
16+
with testing.postgresql.Postgresql() as postgresql:
17+
yield postgresql
18+
19+
20+
@pytest.fixture()
21+
def db_url(postgres_db):
22+
return postgres_db.url()
23+
24+
25+
@pytest.fixture()
26+
def sanitized_db_url(postgres_db):
27+
dsn = postgres_db.dsn()
28+
return 'postgresql://{user}@{host}:{port}/{db}'.format(
29+
user=dsn['user'],
30+
host=dsn['host'],
31+
port=dsn['port'],
32+
db=dsn['database'],
33+
)
34+
35+
36+
def test_all(session, sanitized_db_url):
37+
""" Test calling all() on get all records.
38+
Verify we run the query and return the SQL as metdata"""
39+
session.query(User).all()
40+
assert len(xray_recorder.current_segment().subsegments) == 1
41+
sql_meta = xray_recorder.current_segment().subsegments[0].sql
42+
assert sql_meta['url'] == sanitized_db_url
43+
assert sql_meta['sanitized_query'].startswith('SELECT')
44+
assert sql_meta['sanitized_query'].endswith('FROM users')
45+
46+
47+
def test_insert_on_conflict_renders(connection):
48+
statement = pg_insert(User).values(name='John', fullname="John Doe", password='123456')
49+
statement = statement.on_conflict_do_nothing()
50+
51+
connection.execute(statement)
52+
53+
assert len(xray_recorder.current_segment().subsegments) == 1
54+
sql_meta = xray_recorder.current_segment().subsegments[0].sql
55+
56+
assert sql_meta['sanitized_query'].startswith('INSERT INTO users')
57+
assert 'ON CONFLICT DO NOTHING' in sql_meta['sanitized_query']

tests/ext/sqlalchemy_core/test_sqlalchemy_core.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .test_base import User, session, engine, connection
1+
from .test_base import User, session, db_url, engine, connection
22
from sqlalchemy.sql.expression import Insert, Delete
33
from aws_xray_sdk.core import xray_recorder
44

tests/ext/sqlalchemy_core/test_sqlalchemy_core_2.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .test_base import User, session, engine, connection
1+
from .test_base import User, session, db_url, engine, connection
22
from sqlalchemy.sql.expression import select
33
from aws_xray_sdk.core import xray_recorder
44

0 commit comments

Comments
 (0)