soda-sqlserver 4.22.0__tar.gz → 4.23.1__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.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soda-sqlserver
3
- Version: 4.22.0
3
+ Version: 4.23.1
4
4
  Summary: Soda SQL Server V4
5
5
  Author-email: "Soda Data N.V." <info@soda.io>
6
6
  License: Proprietary
7
7
  Requires-Python: >=3.10
8
- Requires-Dist: soda-core==4.22.0
8
+ Requires-Dist: soda-core==4.23.1
9
9
  Requires-Dist: pyodbc
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "soda-sqlserver"
3
- version = "4.22.0"
3
+ version = "4.23.1"
4
4
  description = "Soda SQL Server V4"
5
5
  requires-python = ">=3.10"
6
6
  license = {text = "Proprietary"}
@@ -8,7 +8,7 @@ authors = [
8
8
  {name = "Soda Data N.V.", email = "info@soda.io"}
9
9
  ]
10
10
  dependencies = [
11
- "soda-core==4.22.0",
11
+ "soda-core==4.23.1",
12
12
  "pyodbc",
13
13
  ]
14
14
 
@@ -10,7 +10,6 @@ from soda_core.common.logging_constants import soda_logger
10
10
  from soda_core.common.metadata_types import SodaDataTypeName, SqlDataType
11
11
  from soda_core.common.sql_ast import (
12
12
  ADD_INTERVAL,
13
- AND,
14
13
  COLUMN,
15
14
  COUNT,
16
15
  CREATE_TABLE,
@@ -23,7 +22,6 @@ from soda_core.common.sql_ast import (
23
22
  DROP_TABLE_IF_EXISTS,
24
23
  DROP_VIEW,
25
24
  DROP_VIEW_IF_EXISTS,
26
- FROM,
27
25
  INSERT_INTO,
28
26
  INSERT_INTO_VIA_SELECT,
29
27
  INTO,
@@ -32,25 +30,19 @@ from soda_core.common.sql_ast import (
32
30
  OFFSET,
33
31
  PERCENTILE_WITHIN_GROUP,
34
32
  RANDOM,
35
- REGEX_LIKE,
36
- SELECT,
37
- STAR,
38
33
  STRING_HASH,
39
34
  TIME_DELTA,
40
35
  TUPLE,
41
36
  VALUES,
42
- WHERE,
43
37
  WITH,
44
- SqlExpressionStr,
38
+ SqlColumnTerm,
45
39
  seconds_per_time_bucket,
46
40
  )
47
41
  from soda_core.common.sql_dialect import SqlDialect
48
42
  from soda_sqlserver.common.data_sources.sqlserver_data_source_connection import (
49
43
  SqlServerDataSource as SqlServerDataSourceModel,
50
44
  )
51
- from soda_sqlserver.common.data_sources.sqlserver_data_source_connection import (
52
- SqlServerDataSourceConnection,
53
- )
45
+ from soda_sqlserver.common.data_sources.sqlserver_data_source_connection import SqlServerDataSourceConnection
54
46
 
55
47
  logger: logging.Logger = soda_logger
56
48
 
@@ -175,7 +167,12 @@ class SqlServerSqlDialect(SqlDialect, sqlglot_dialect="tsql"):
175
167
  limit_element: LIMIT = [
176
168
  select_element for select_element in select_elements if isinstance(select_element, LIMIT)
177
169
  ][0]
178
- select_sql_lines[0] = select_sql_lines[0].replace("SELECT ", f"SELECT TOP {limit_element.limit} ")
170
+ # T-SQL grammar is `SELECT [ALL | DISTINCT] [TOP n] <fields>`, so TOP goes after
171
+ # DISTINCT when the base rendered a distinct select.
172
+ select_prefix: str = "SELECT DISTINCT " if select_sql_lines[0].startswith("SELECT DISTINCT ") else "SELECT "
173
+ select_sql_lines[0] = select_sql_lines[0].replace(
174
+ select_prefix, f"{select_prefix}TOP {limit_element.limit} ", 1
175
+ )
179
176
  return select_sql_lines
180
177
 
181
178
  def __requires_select_top(self, select_elements: list) -> bool:
@@ -307,19 +304,23 @@ class SqlServerSqlDialect(SqlDialect, sqlglot_dialect="tsql"):
307
304
  return ", ".join(self.build_expression_sql(e) for e in tuple.expressions)
308
305
  return super()._build_tuple_sql(tuple)
309
306
 
310
- def _build_regex_like_sql(self, matches: REGEX_LIKE) -> str:
311
- expression: str = self.build_expression_sql(matches.expression)
312
- regex_pattern = matches.regex_pattern
307
+ def _rewrite_regex_pattern(self, regex_pattern: str) -> str:
313
308
  # alpha expansion doesn't work properly for case sensitive ranges in SQLServer
314
- # this is quite a hack to fit the common use-cases. generally regex's are only partially supported anyway
309
+ # this is quite a hack to fit the common use-cases. generally regex's are only
310
+ # partially supported anyway
315
311
  regex_pattern = regex_pattern.replace("a-z", "abcdefghijklmnopqrstuvwxyz")
316
312
  regex_pattern = regex_pattern.replace("A-Z", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
313
+ # PATINDEX matches a substring, so the pattern is wrapped rather than anchored.
314
+ # Wrapping here rather than around the rendered literal keeps the % inside the
315
+ # quotes that the base escaping puts on.
316
+ return f"%{regex_pattern}%"
317
+
318
+ def _regex_like_sql(self, expression: str, pattern: str) -> str:
317
319
  # collations define rules for sorting strings and distinguishing similar characters
318
320
  # see: https://learn.microsoft.com/en-us/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver17
319
321
  # CS: Case sensitive; AS: Accent sensitive
320
322
  # The default is SQL_Latin1_General_Cp1_CI_AS (case-insensitive), we replcae with a case sensitive collation
321
- pattern_literal: str = self.literal_string(f"%{regex_pattern}%")
322
- return f"PATINDEX ({pattern_literal}, {expression} COLLATE SQL_Latin1_General_Cp1_CS_AS) > 0"
323
+ return f"PATINDEX ({pattern}, {expression} COLLATE SQL_Latin1_General_Cp1_CS_AS) > 0"
323
324
 
324
325
  def supports_regex_advanced(self) -> bool:
325
326
  return False
@@ -330,23 +331,25 @@ class SqlServerSqlDialect(SqlDialect, sqlglot_dialect="tsql"):
330
331
  def select_all_paginated_sql(
331
332
  self,
332
333
  dataset_identifier: DatasetIdentifier,
333
- columns: list[str],
334
+ columns: list[SqlColumnTerm],
334
335
  filter: Optional[str],
335
- order_by: list[str],
336
+ order_by: list[SqlColumnTerm],
336
337
  limit: int,
337
338
  offset: int,
338
339
  normalize_key_columns: frozenset[str] = frozenset(),
340
+ distinct: bool = False,
339
341
  ) -> str:
340
- where_clauses = []
341
-
342
- if filter:
343
- where_clauses.append(SqlExpressionStr(filter))
344
-
342
+ # Same elements as the base paginator (including its distinct x normalize composition),
343
+ # but T-SQL spells the page as OFFSET n ROWS FETCH NEXT m ROWS ONLY, so OFFSET leads.
345
344
  statements = [
346
- SELECT(columns or [STAR()]),
347
- FROM(table_name=dataset_identifier.dataset_name, table_prefix=dataset_identifier.prefixes),
348
- WHERE.optional(AND.optional(where_clauses)),
349
- *[term for c in order_by for term in self._order_by_key(c, normalize_key_columns)],
345
+ *self._paginated_select_statements(
346
+ dataset_identifier=dataset_identifier,
347
+ columns=columns,
348
+ filter=filter,
349
+ order_by=order_by,
350
+ normalize_key_columns=normalize_key_columns,
351
+ distinct=distinct,
352
+ ),
350
353
  OFFSET(offset),
351
354
  LIMIT(limit),
352
355
  ]
@@ -16,9 +16,7 @@ from soda_core.common.data_source_results import QueryResult
16
16
  from soda_core.common.exceptions import DataSourceConnectionException
17
17
  from soda_core.common.logging_constants import soda_logger
18
18
  from soda_core.model.data_source.data_source import DataSourceBase
19
- from soda_core.model.data_source.data_source_connection_properties import (
20
- DataSourceConnectionProperties,
21
- )
19
+ from soda_core.model.data_source.data_source_connection_properties import DataSourceConnectionProperties
22
20
 
23
21
  logger: logging.Logger = soda_logger
24
22
 
@@ -5,10 +5,7 @@ from typing import Optional
5
5
 
6
6
  from helpers.data_source_test_helper import DataSourceTestHelper
7
7
  from soda_core.common.sql_ast import DROP_TABLE, DROP_VIEW
8
- from soda_sqlserver.common.data_sources.sqlserver_data_source import (
9
- SqlServerDataSourceImpl,
10
- SqlServerSqlDialect,
11
- )
8
+ from soda_sqlserver.common.data_sources.sqlserver_data_source import SqlServerDataSourceImpl, SqlServerSqlDialect
12
9
 
13
10
 
14
11
  class SqlServerDataSourceTestHelper(DataSourceTestHelper):
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soda-sqlserver
3
- Version: 4.22.0
3
+ Version: 4.23.1
4
4
  Summary: Soda SQL Server V4
5
5
  Author-email: "Soda Data N.V." <info@soda.io>
6
6
  License: Proprietary
7
7
  Requires-Python: >=3.10
8
- Requires-Dist: soda-core==4.22.0
8
+ Requires-Dist: soda-core==4.23.1
9
9
  Requires-Dist: pyodbc
@@ -0,0 +1,2 @@
1
+ soda-core==4.23.1
2
+ pyodbc
@@ -1,2 +0,0 @@
1
- soda-core==4.22.0
2
- pyodbc