From 1f8b568084721eb93743014e7224e1bcea8b6e1c Mon Sep 17 00:00:00 2001 From: Nicola Coretti Date: Mon, 10 Jun 2024 16:10:14 +0200 Subject: [PATCH 1/2] Add json tests --- pyproject.toml | 1 + test/integration/json_test.py | 139 ++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 test/integration/json_test.py diff --git a/pyproject.toml b/pyproject.toml index 31e7cab..48300de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,5 +79,6 @@ markers = [ "format: tests related to f-string based statement formatting.", "transaction: tests related to transaction management.", "exceptions: tests related to exceptions in pyexasol.", + "json: tests related to json serialization in pyexasol.", ] diff --git a/test/integration/json_test.py b/test/integration/json_test.py new file mode 100644 index 0000000..61a3821 --- /dev/null +++ b/test/integration/json_test.py @@ -0,0 +1,139 @@ +import pytest +import pyexasol +import decimal + +from inspect import cleandoc + + +@pytest.fixture +def connection_factory(dsn, user, password, schema): + connections = [] + + def factory(json_lib): + con = pyexasol.connect( + dsn=dsn, + user=user, + password=password, + schema=schema, + json_lib=json_lib, + ) + connections.append(con) + return con + + yield factory + + for c in connections: + c.close() + + +@pytest.fixture +def table(connection): + name = "edge_case" + ddl = cleandoc( + f"""CREATE OR REPLACE TABLE {name} + ( + dec36_0 DECIMAL(36,0), + dec36_36 DECIMAL(36,36), + dbl DOUBLE, + bl BOOLEAN, + dt DATE, + ts TIMESTAMP, + var100 VARCHAR(100), + var2000000 VARCHAR(2000000) + ) + """ + ) + connection.execute(ddl) + connection.commit() + + yield name + + delete_stmt = f"DROP TABLE IF EXISTS {name};" + connection.execute(delete_stmt) + connection.commit() + + +@pytest.fixture +def edge_cases(): + return [ + # Biggest values + { + "DEC36_0": decimal.Decimal("+" + ("9" * 36)), + "DEC36_36": decimal.Decimal("+0." + ("9" * 36)), + "DBL": 1.7e308, + "BL": True, + "DT": "9999-12-31", + "TS": "9999-12-31 23:59:59.999", + "VAR100": "ひ" * 100, + "VAR2000000": "ひ" * 2000000, + }, + # Smallest values + { + "DEC36_0": decimal.Decimal("-" + ("9" * 36)), + "DEC36_36": decimal.Decimal("-0." + ("9" * 36)), + "DBL": -1.7e308, + "BL": False, + "DT": "0001-01-01", + "TS": "0001-01-01 00:00:00", + "VAR100": "", + "VAR2000000": "ひ", + }, + # All nulls + { + "DEC36_0": None, + "DEC36_36": None, + "DBL": None, + "BL": None, + "DT": None, + "TS": None, + "VAR100": None, + "VAR2000000": None, + }, + ] + + +@pytest.mark.json +@pytest.mark.parametrize("json_lib", ["orjson", "ujson", "rapidjson"]) +def test_insert(table, connection_factory, edge_cases, json_lib): + connection = connection_factory(json_lib) + insert_stmt = ( + "INSERT INTO edge_case VALUES" + "({DEC36_0!d}, {DEC36_36!d}, {DBL!f}, {BL}, {DT}, {TS}, {VAR100}, {VAR2000000})" + ) + for edge_case in edge_cases: + connection.execute(insert_stmt, edge_case) + + expected = len(edge_cases) + actual = connection.execute(f"SELECT COUNT(*) FROM {table};").fetchval() + + assert actual == expected + + +@pytest.mark.json +@pytest.mark.parametrize("json_lib", ["orjson", "ujson", "rapidjson"]) +def test_select(table, connection_factory, edge_cases, json_lib): + connection = connection_factory(json_lib) + + insert_stmt = ( + "INSERT INTO edge_case VALUES" + "({DEC36_0!d}, {DEC36_36!d}, {DBL!f}, {BL}, {DT}, {TS}, {VAR100}, {VAR2000000})" + ) + for edge_case in edge_cases: + connection.execute(insert_stmt, edge_case) + + select_stmt = ( + "SELECT DEC36_0, DEC36_36, DBL, BL, DT, TS, VAR100, LENGTH(VAR2000000) " + "AS LEN_VAR FROM EDGE_CASE" + ) + + expected = { + # Biggest values + ("9" * 36, f"0.{'9' * 36}", 1.7e308, True, "9999-12-31", "9999-12-31 23:59:59.999000", "ひ" * 100, 2000000), + # Smallest values + (f"-{'9' * 36}", f"-0.{'9' * 36}", -1.7e308, False, "0001-01-01", "0001-01-01 00:00:00.000000", None, 1), + # All nulls + (None, None, None, None, None, None, None, None), + } + actual = set(connection.execute(select_stmt).fetchall()) + + assert actual == expected From 653a637e98bc2ad28e0fab41a7b23c36c49e189c Mon Sep 17 00:00:00 2001 From: Nicola Coretti Date: Tue, 11 Jun 2024 09:08:31 +0200 Subject: [PATCH 2/2] Update references to python-toolbox action --- .github/workflows/checks.yml | 4 ++-- .github/workflows/examples.yml | 2 +- .github/workflows/ssl_cert.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index dcc7cef..bf0540f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Python & Poetry Environment - uses: exasol/python-toolbox/.github/actions/python-environment@0.7.0 + uses: exasol/python-toolbox/.github/actions/python-environment@0.13.0 with: python-version: ${{ matrix.python-version }} @@ -43,7 +43,7 @@ jobs: uses: actions/checkout@v4 - name: Setup Python & Poetry Environment - uses: exasol/python-toolbox/.github/actions/python-environment@0.7.0 + uses: exasol/python-toolbox/.github/actions/python-environment@0.13.0 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 0709cee..c5ac225 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v2 - name: "Setup Python & Poetry Environment" - uses: exasol/python-toolbox/.github/actions/python-environment@0.7.0 + uses: exasol/python-toolbox/.github/actions/python-environment@0.13.0 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/ssl_cert.yml b/.github/workflows/ssl_cert.yml index 394b5f0..6c8464e 100644 --- a/.github/workflows/ssl_cert.yml +++ b/.github/workflows/ssl_cert.yml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v2 - name: "Setup Python & Poetry Environment" - uses: exasol/python-toolbox/.github/actions/python-environment@0.7.0 + uses: exasol/python-toolbox/.github/actions/python-environment@0.13.0 with: python-version: ${{ matrix.python-version }}