fakesnow 0.9.13__py3-none-any.whl → 0.9.15__py3-none-any.whl

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/fakes.py CHANGED
@@ -175,7 +175,7 @@ class FakeSnowflakeCursor:
175
175
  .transform(transforms.to_timestamp_ntz)
176
176
  .transform(transforms.to_timestamp)
177
177
  .transform(transforms.object_construct)
178
- .transform(transforms.timestamp_ntz_ns)
178
+ .transform(transforms.timestamp_ntz)
179
179
  .transform(transforms.float_to_double)
180
180
  .transform(transforms.integer_precision)
181
181
  .transform(transforms.extract_text_length)
@@ -198,6 +198,7 @@ class FakeSnowflakeCursor:
198
198
  .transform(transforms.create_user)
199
199
  .transform(transforms.sha256)
200
200
  .transform(transforms.create_clone)
201
+ .transform(transforms.alias_in_join)
201
202
  )
202
203
 
203
204
  def _execute(
@@ -296,6 +297,9 @@ class FakeSnowflakeCursor:
296
297
  elif cmd == "CREATE TABLE" and ident:
297
298
  result_sql = SQL_CREATED_TABLE.substitute(name=ident)
298
299
 
300
+ elif cmd.startswith("ALTER") and ident:
301
+ result_sql = SQL_SUCCESS
302
+
299
303
  elif cmd == "CREATE VIEW" and ident:
300
304
  result_sql = SQL_CREATED_VIEW.substitute(name=ident)
301
305
 
fakesnow/transforms.py CHANGED
@@ -13,6 +13,25 @@ MISSING_DATABASE = "missing_database"
13
13
  SUCCESS_NOP = sqlglot.parse_one("SELECT 'Statement executed successfully.'")
14
14
 
15
15
 
16
+ def alias_in_join(expression: exp.Expression) -> exp.Expression:
17
+ if (
18
+ isinstance(expression, exp.Select)
19
+ and (aliases := {e.args.get("alias"): e for e in expression.expressions if isinstance(e, exp.Alias)})
20
+ and (joins := expression.args.get("joins"))
21
+ ):
22
+ j: exp.Join
23
+ for j in joins:
24
+ if (
25
+ (on := j.args.get("on"))
26
+ and (col := on.this)
27
+ and (isinstance(col, exp.Column))
28
+ and (alias := aliases.get(col.this))
29
+ ):
30
+ col.args["this"] = alias.this
31
+
32
+ return expression
33
+
34
+
16
35
  def array_size(expression: exp.Expression) -> exp.Expression:
17
36
  if isinstance(expression, exp.ArraySize):
18
37
  # case is used to convert 0 to null, because null is returned by duckdb when no case matches
@@ -350,17 +369,13 @@ def extract_comment_on_table(expression: exp.Expression) -> exp.Expression:
350
369
  return new
351
370
  elif (
352
371
  isinstance(expression, exp.AlterTable)
353
- and (sexp := expression.find(exp.Set))
354
- and not sexp.args["tag"]
355
- and (eq := sexp.find(exp.EQ))
356
- and (eid := eq.find(exp.Identifier))
357
- and isinstance(eid.this, str)
358
- and eid.this.upper() == "COMMENT"
359
- and (lit := eq.find(exp.Literal))
372
+ and (sexp := expression.find(exp.AlterSet))
373
+ and (scp := sexp.find(exp.SchemaCommentProperty))
374
+ and isinstance(scp.this, exp.Literal)
360
375
  and (table := expression.find(exp.Table))
361
376
  ):
362
377
  new = SUCCESS_NOP.copy()
363
- new.args["table_comment"] = (table, lit.this)
378
+ new.args["table_comment"] = (table, scp.this.this)
364
379
  return new
365
380
 
366
381
  return expression
@@ -596,15 +611,12 @@ def json_extract_cast_as_varchar(expression: exp.Expression) -> exp.Expression:
596
611
  """
597
612
  if (
598
613
  isinstance(expression, exp.Cast)
599
- and (to := expression.to)
600
- and isinstance(to, exp.DataType)
601
- and to.this in {exp.DataType.Type.VARCHAR, exp.DataType.Type.TEXT}
602
614
  and (je := expression.this)
603
615
  and isinstance(je, exp.JSONExtract)
604
616
  and (path := je.expression)
605
617
  and isinstance(path, exp.JSONPath)
606
618
  ):
607
- return exp.JSONExtractScalar(this=je.this, expression=path)
619
+ je.replace(exp.JSONExtractScalar(this=je.this, expression=path))
608
620
  return expression
609
621
 
610
622
 
@@ -937,7 +949,7 @@ def tag(expression: exp.Expression) -> exp.Expression:
937
949
 
938
950
  if isinstance(expression, exp.AlterTable) and (actions := expression.args.get("actions")):
939
951
  for a in actions:
940
- if isinstance(a, exp.Set) and a.args["tag"]:
952
+ if isinstance(a, exp.AlterSet) and a.args.get("tag"):
941
953
  return SUCCESS_NOP
942
954
  elif (
943
955
  isinstance(expression, exp.Command)
@@ -947,6 +959,13 @@ def tag(expression: exp.Expression) -> exp.Expression:
947
959
  ):
948
960
  # alter table modify column set tag
949
961
  return SUCCESS_NOP
962
+ elif (
963
+ isinstance(expression, exp.Create)
964
+ and (kind := expression.args.get("kind"))
965
+ and isinstance(kind, str)
966
+ and kind.upper() == "TAG"
967
+ ):
968
+ return SUCCESS_NOP
950
969
 
951
970
  return expression
952
971
 
@@ -1114,17 +1133,15 @@ def to_timestamp_ntz(expression: exp.Expression) -> exp.Expression:
1114
1133
  return expression
1115
1134
 
1116
1135
 
1117
- def timestamp_ntz_ns(expression: exp.Expression) -> exp.Expression:
1118
- """Convert timestamp_ntz(9) to timestamp_ntz.
1136
+ def timestamp_ntz(expression: exp.Expression) -> exp.Expression:
1137
+ """Convert timestamp_ntz (snowflake) to timestamp (duckdb).
1119
1138
 
1120
- To compensate for https://github.com/duckdb/duckdb/issues/7980
1139
+ NB: timestamp_ntz defaults to nanosecond precision (ie: NTZ(9)). The duckdb equivalent is TIMESTAMP_NS.
1140
+ However we use TIMESTAMP (ie: microsecond precision) here rather than TIMESTAMP_NS to avoid
1141
+ https://github.com/duckdb/duckdb/issues/7980 in test_write_pandas_timestamp_ntz.
1121
1142
  """
1122
1143
 
1123
- if (
1124
- isinstance(expression, exp.DataType)
1125
- and expression.this == exp.DataType.Type.TIMESTAMPNTZ
1126
- and exp.DataTypeParam(this=exp.Literal(this="9", is_string=False)) in expression.expressions
1127
- ):
1144
+ if isinstance(expression, exp.DataType) and expression.this == exp.DataType.Type.TIMESTAMPNTZ:
1128
1145
  return exp.DataType(this=exp.DataType.Type.TIMESTAMP)
1129
1146
 
1130
1147
  return expression
@@ -1173,7 +1190,6 @@ def try_parse_json(expression: exp.Expression) -> exp.Expression:
1173
1190
  return expression
1174
1191
 
1175
1192
 
1176
- # sqlglot.parse_one("create table example(date TIMESTAMP_NTZ(9));", read="snowflake")
1177
1193
  def semi_structured_types(expression: exp.Expression) -> exp.Expression:
1178
1194
  """Convert OBJECT, ARRAY, and VARIANT types to duckdb compatible types.
1179
1195
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fakesnow
3
- Version: 0.9.13
3
+ Version: 0.9.15
4
4
  Summary: Fake Snowflake Connector for Python. Run, mock and test Snowflake DB locally.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -210,10 +210,10 @@ Classifier: License :: OSI Approved :: MIT License
210
210
  Requires-Python: >=3.9
211
211
  Description-Content-Type: text/markdown
212
212
  License-File: LICENSE
213
- Requires-Dist: duckdb ~=0.10.0
213
+ Requires-Dist: duckdb ~=0.10.3
214
214
  Requires-Dist: pyarrow
215
215
  Requires-Dist: snowflake-connector-python
216
- Requires-Dist: sqlglot ~=23.14.0
216
+ Requires-Dist: sqlglot ~=24.1.0
217
217
  Provides-Extra: dev
218
218
  Requires-Dist: build ~=1.0 ; extra == 'dev'
219
219
  Requires-Dist: pandas-stubs ; extra == 'dev'
@@ -3,16 +3,16 @@ fakesnow/__main__.py,sha256=GDrGyNTvBFuqn_UfDjKs7b3LPtU6gDv1KwosVDrukIM,76
3
3
  fakesnow/checks.py,sha256=-QMvdcrRbhN60rnzxLBJ0IkUBWyLR8gGGKKmCS0w9mA,2383
4
4
  fakesnow/cli.py,sha256=9qfI-Ssr6mo8UmIlXkUAOz2z2YPBgDsrEVaZv9FjGFs,2201
5
5
  fakesnow/expr.py,sha256=CAxuYIUkwI339DQIBzvFF0F-m1tcVGKEPA5rDTzmH9A,892
6
- fakesnow/fakes.py,sha256=q_mTOnNqYdXfrHohTRarGQG1ygh-QXV-7mCptpJ1OQ8,30231
6
+ fakesnow/fakes.py,sha256=qBbw0NagjLN00cUfrOIW7--f2AE0vKLGpWDAQIkjUww,30371
7
7
  fakesnow/fixtures.py,sha256=G-NkVeruSQAJ7fvSS2fR2oysUn0Yra1pohHlOvacKEk,455
8
8
  fakesnow/global_database.py,sha256=WTVIP1VhNvdCeX7TQncX1TRpGQU5rBf5Pbxim40zeSU,1399
9
9
  fakesnow/info_schema.py,sha256=CdIcGXHEQ_kmEAzdQKvA-PX41LA6wlK-4p1J45qgKYA,6266
10
10
  fakesnow/macros.py,sha256=pX1YJDnQOkFJSHYUjQ6ErEkYIKvFI6Ncz_au0vv1csA,265
11
11
  fakesnow/py.typed,sha256=B-DLSjYBi7pkKjwxCSdpVj2J02wgfJr-E7B1wOUyxYU,80
12
- fakesnow/transforms.py,sha256=gQJVehhUXNecnCe8GVC5EM9MBsSPNUHjz9_djUAyJUI,50648
13
- fakesnow-0.9.13.dist-info/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
14
- fakesnow-0.9.13.dist-info/METADATA,sha256=1j1kYYfrf6tztJ24t45oMew6ShCqwnP8VDu00I4sbag,17841
15
- fakesnow-0.9.13.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
16
- fakesnow-0.9.13.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
17
- fakesnow-0.9.13.dist-info/top_level.txt,sha256=500evXI1IFX9so82cizGIEMHAb_dJNPaZvd2H9dcKTA,24
18
- fakesnow-0.9.13.dist-info/RECORD,,
12
+ fakesnow/transforms.py,sha256=8DwHoJ09U2915DovAH_ul0_5WzlUkHYLLK1njyhER4s,51230
13
+ fakesnow-0.9.15.dist-info/LICENSE,sha256=kW-7NWIyaRMQiDpryfSmF2DObDZHGR1cJZ39s6B1Svg,11344
14
+ fakesnow-0.9.15.dist-info/METADATA,sha256=tJx48TlbZ2Pf62qWto4JEbx1h_Ypo6FJqa0dugqjnbw,17840
15
+ fakesnow-0.9.15.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
16
+ fakesnow-0.9.15.dist-info/entry_points.txt,sha256=2riAUgu928ZIHawtO8EsfrMEJhi-EH-z_Vq7Q44xKPM,47
17
+ fakesnow-0.9.15.dist-info/top_level.txt,sha256=500evXI1IFX9so82cizGIEMHAb_dJNPaZvd2H9dcKTA,24
18
+ fakesnow-0.9.15.dist-info/RECORD,,