fakesnow 0.7.1__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fakesnow-0.7.1/fakesnow.egg-info → fakesnow-0.8.0}/PKG-INFO +1 -1
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/fakes.py +2 -5
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/info_schema.py +1 -2
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/transforms.py +8 -9
- {fakesnow-0.7.1 → fakesnow-0.8.0/fakesnow.egg-info}/PKG-INFO +1 -1
- {fakesnow-0.7.1 → fakesnow-0.8.0}/pyproject.toml +1 -1
- {fakesnow-0.7.1 → fakesnow-0.8.0}/tests/test_fakes.py +38 -13
- {fakesnow-0.7.1 → fakesnow-0.8.0}/tests/test_transforms.py +1 -1
- {fakesnow-0.7.1 → fakesnow-0.8.0}/LICENSE +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/MANIFEST.in +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/README.md +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/__init__.py +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/checks.py +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/expr.py +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/fixtures.py +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow/py.typed +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow.egg-info/SOURCES.txt +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow.egg-info/dependency_links.txt +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow.egg-info/requires.txt +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/fakesnow.egg-info/top_level.txt +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/setup.cfg +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/tests/test_checks.py +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/tests/test_expr.py +0 -0
- {fakesnow-0.7.1 → fakesnow-0.8.0}/tests/test_patch.py +0 -0
@@ -322,13 +322,10 @@ class FakeSnowflakeCursor:
|
|
322
322
|
return ResultMetadata(
|
323
323
|
name=column_name, type_code=12, display_size=None, internal_size=None, precision=0, scale=9, is_nullable=True # noqa: E501
|
324
324
|
)
|
325
|
-
elif column_type == "JSON[]":
|
326
|
-
return ResultMetadata(
|
327
|
-
name=column_name, type_code=10, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True # noqa: E501
|
328
|
-
)
|
329
325
|
elif column_type == "JSON":
|
326
|
+
# TODO: correctly map OBJECT and ARRAY see https://github.com/tekumara/fakesnow/issues/26
|
330
327
|
return ResultMetadata(
|
331
|
-
name=column_name, type_code=
|
328
|
+
name=column_name, type_code=5, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True # noqa: E501
|
332
329
|
)
|
333
330
|
else:
|
334
331
|
# TODO handle more types
|
@@ -40,8 +40,7 @@ case when starts_with(data_type, 'DECIMAL') or data_type='BIGINT' then 'NUMBER'
|
|
40
40
|
when data_type='DOUBLE' then 'FLOAT'
|
41
41
|
when data_type='BLOB' then 'BINARY'
|
42
42
|
when data_type='TIMESTAMP' then 'TIMESTAMP_NTZ'
|
43
|
-
when data_type='JSON
|
44
|
-
when data_type='JSON' then 'OBJECT'
|
43
|
+
when data_type='JSON' then 'VARIANT'
|
45
44
|
else data_type end as data_type,
|
46
45
|
ext_character_maximum_length as character_maximum_length, ext_character_octet_length as character_octet_length,
|
47
46
|
case when data_type='BIGINT' then 38
|
@@ -578,15 +578,14 @@ def semi_structured_types(expression: exp.Expression) -> exp.Expression:
|
|
578
578
|
exp.Expression: The transformed expression.
|
579
579
|
"""
|
580
580
|
|
581
|
-
if isinstance(expression, exp.DataType)
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
return new
|
581
|
+
if isinstance(expression, exp.DataType) and expression.this in [
|
582
|
+
exp.DataType.Type.ARRAY,
|
583
|
+
exp.DataType.Type.OBJECT,
|
584
|
+
exp.DataType.Type.VARIANT,
|
585
|
+
]:
|
586
|
+
new = expression.copy()
|
587
|
+
new.args["this"] = exp.DataType.Type.JSON
|
588
|
+
return new
|
590
589
|
|
591
590
|
return expression
|
592
591
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
import datetime
|
4
4
|
import json
|
5
|
+
from collections.abc import Sequence
|
5
6
|
from decimal import Decimal
|
6
7
|
|
7
8
|
import pandas as pd
|
@@ -205,7 +206,7 @@ def test_describe(cur: snowflake.connector.cursor.SnowflakeCursor):
|
|
205
206
|
XINT INT, XINTEGER INTEGER, XBIGINT BIGINT, XSMALLINT SMALLINT, XTINYINT TINYINT, XBYTEINT BYTEINT,
|
206
207
|
XVARCHAR20 VARCHAR(20), XVARCHAR VARCHAR, XTEXT TEXT,
|
207
208
|
XTIMESTAMP TIMESTAMP, XTIMESTAMP_NTZ9 TIMESTAMP_NTZ(9), XDATE DATE, XTIME TIME,
|
208
|
-
XBINARY BINARY, XARRAY ARRAY, XOBJECT OBJECT
|
209
|
+
XBINARY BINARY, /* XARRAY ARRAY, XOBJECT OBJECT */ XVARIANT VARIANT
|
209
210
|
)
|
210
211
|
"""
|
211
212
|
)
|
@@ -233,8 +234,10 @@ def test_describe(cur: snowflake.connector.cursor.SnowflakeCursor):
|
|
233
234
|
ResultMetadata(name='XDATE', type_code=3, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True),
|
234
235
|
ResultMetadata(name='XTIME', type_code=12, display_size=None, internal_size=None, precision=0, scale=9, is_nullable=True),
|
235
236
|
ResultMetadata(name='XBINARY', type_code=11, display_size=None, internal_size=8388608, precision=None, scale=None, is_nullable=True),
|
236
|
-
|
237
|
-
ResultMetadata(name='
|
237
|
+
# TODO: handle ARRAY and OBJECT see https://github.com/tekumara/fakesnow/issues/26
|
238
|
+
# ResultMetadata(name='XARRAY', type_code=10, display_size=None, internal_size=16777216, precision=None, scale=None, is_nullable=True),
|
239
|
+
# ResultMetadata(name='XOBJECT', type_code=9, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True),
|
240
|
+
ResultMetadata(name='XVARIANT', type_code=5, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True),
|
238
241
|
]
|
239
242
|
# fmt: on
|
240
243
|
|
@@ -247,6 +250,19 @@ def test_describe(cur: snowflake.connector.cursor.SnowflakeCursor):
|
|
247
250
|
cur.execute("select * from example where XNUMBER = %s", (1,))
|
248
251
|
assert cur.description == expected_metadata
|
249
252
|
|
253
|
+
# test semi-structured ops return variant ie: type_code=5
|
254
|
+
# fmt: off
|
255
|
+
assert (
|
256
|
+
cur.describe("SELECT ['A', 'B'][0] as array_index, OBJECT_CONSTRUCT('k','v1')['k'] as object_key, ARRAY_CONSTRUCT('foo')::VARIANT[0] as variant_key")
|
257
|
+
== [
|
258
|
+
# NB: snowflake returns internal_size = 16777216 for all columns
|
259
|
+
ResultMetadata(name="ARRAY_INDEX", type_code=5, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True),
|
260
|
+
ResultMetadata(name="OBJECT_KEY", type_code=5, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True),
|
261
|
+
ResultMetadata(name="VARIANT_KEY", type_code=5, display_size=None, internal_size=None, precision=None, scale=None, is_nullable=True)
|
262
|
+
]
|
263
|
+
)
|
264
|
+
# fmt: on
|
265
|
+
|
250
266
|
|
251
267
|
def test_describe_info_schema_columns(cur: snowflake.connector.cursor.SnowflakeCursor):
|
252
268
|
# test we can handle the column types returned from the info schema, which are created by duckdb
|
@@ -420,7 +436,7 @@ def test_information_schema_columns_other(cur: snowflake.connector.cursor.Snowfl
|
|
420
436
|
"""
|
421
437
|
create or replace table example (
|
422
438
|
XTIMESTAMP TIMESTAMP, XTIMESTAMP_NTZ9 TIMESTAMP_NTZ(9), XDATE DATE, XTIME TIME,
|
423
|
-
XBINARY BINARY, XARRAY ARRAY, XOBJECT OBJECT
|
439
|
+
XBINARY BINARY, /* XARRAY ARRAY, XOBJECT OBJECT */ XVARIANT VARIANT
|
424
440
|
)
|
425
441
|
"""
|
426
442
|
)
|
@@ -438,8 +454,10 @@ def test_information_schema_columns_other(cur: snowflake.connector.cursor.Snowfl
|
|
438
454
|
("XDATE", "DATE"),
|
439
455
|
("XTIME", "TIME"),
|
440
456
|
("XBINARY", "BINARY"),
|
441
|
-
|
442
|
-
("
|
457
|
+
# TODO: support these types https://github.com/tekumara/fakesnow/issues/27
|
458
|
+
# ("XARRAY", "ARRAY"),
|
459
|
+
# ("XOBJECT", "OBJECT"),
|
460
|
+
("XVARIANT", "VARIANT"),
|
443
461
|
]
|
444
462
|
|
445
463
|
|
@@ -547,18 +565,25 @@ def test_schema_drop(cur: snowflake.connector.cursor.SnowflakeCursor):
|
|
547
565
|
|
548
566
|
|
549
567
|
def test_semi_structured_types(cur: snowflake.connector.cursor.SnowflakeCursor):
|
550
|
-
|
568
|
+
def indent(rows: Sequence[tuple]) -> list[tuple]:
|
569
|
+
# indent duckdb json strings to match snowflake json strings
|
570
|
+
return [(json.dumps(json.loads(r[0]), indent=2), *r[1:]) for r in rows]
|
571
|
+
|
572
|
+
cur.execute("create or replace table semis (emails array, name object, notes variant)")
|
551
573
|
cur.execute(
|
552
|
-
"""insert into semis(emails, name, notes) SELECT [
|
574
|
+
"""insert into semis(emails, name, notes) SELECT ['A', 'B'], OBJECT_CONSTRUCT('k','v1'), ARRAY_CONSTRUCT('foo')::VARIANT"""
|
553
575
|
)
|
554
576
|
cur.execute(
|
555
|
-
"""insert into semis(emails, name, notes)
|
577
|
+
"""insert into semis(emails, name, notes) SELECT ['C','D'], parse_json('{"k": "v2"}'), parse_json('{"b": "ar"}')"""
|
556
578
|
)
|
557
579
|
|
558
580
|
# results are returned as strings, because the underlying type is JSON (duckdb) / VARIANT (snowflake)
|
559
581
|
|
582
|
+
cur.execute("select emails from semis")
|
583
|
+
assert indent(cur.fetchall()) == [('[\n "A",\n "B"\n]',), ('[\n "C",\n "D"\n]',)] # type: ignore
|
584
|
+
|
560
585
|
cur.execute("select emails[0] from semis")
|
561
|
-
assert cur.fetchall() == [("
|
586
|
+
assert cur.fetchall() == [('"A"',), ('"C"',)]
|
562
587
|
|
563
588
|
cur.execute("select name['k'] from semis")
|
564
589
|
assert cur.fetchall() == [('"v1"',), ('"v2"',)]
|
@@ -728,12 +753,12 @@ def test_values(conn: snowflake.connector.SnowflakeConnection):
|
|
728
753
|
|
729
754
|
def test_write_pandas(conn: snowflake.connector.SnowflakeConnection):
|
730
755
|
with conn.cursor() as cur:
|
731
|
-
cur.execute("create table customers (ID int, FIRST_NAME varchar, LAST_NAME varchar)")
|
756
|
+
cur.execute("create table customers (ID int, FIRST_NAME varchar, LAST_NAME varchar, ORDERS array)")
|
732
757
|
|
733
758
|
df = pd.DataFrame.from_records(
|
734
759
|
[
|
735
|
-
{"ID": 1, "FIRST_NAME": "Jenny", "LAST_NAME": "P"},
|
736
|
-
{"ID": 2, "FIRST_NAME": "Jasper", "LAST_NAME": "M"},
|
760
|
+
{"ID": 1, "FIRST_NAME": "Jenny", "LAST_NAME": "P", "ORDERS": ["A", "B"]},
|
761
|
+
{"ID": 2, "FIRST_NAME": "Jasper", "LAST_NAME": "M", "ORDERS": ["C", "D"]},
|
737
762
|
]
|
738
763
|
)
|
739
764
|
snowflake.connector.pandas_tools.write_pandas(conn, df, "customers")
|
@@ -163,7 +163,7 @@ def test_semi_structured_types() -> None:
|
|
163
163
|
|
164
164
|
assert (
|
165
165
|
sqlglot.parse_one("CREATE TABLE table1 (name array)").transform(semi_structured_types).sql(dialect="duckdb")
|
166
|
-
== "CREATE TABLE table1 (name JSON
|
166
|
+
== "CREATE TABLE table1 (name JSON)"
|
167
167
|
)
|
168
168
|
|
169
169
|
assert (
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|