soda-postgres 4.1.0__tar.gz → 4.2.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.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soda-postgres
3
- Version: 4.1.0
3
+ Version: 4.2.0
4
4
  Summary: Soda Postgres 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.1.0
8
+ Requires-Dist: soda-core==4.2.0
9
9
  Requires-Dist: psycopg[binary]>=3.2
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "soda-postgres"
3
- version = "4.1.0"
3
+ version = "4.2.0"
4
4
  description = "Soda Postgres 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.1.0",
11
+ "soda-core==4.2.0",
12
12
  "psycopg[binary]>=3.2",
13
13
  ]
14
14
 
@@ -245,103 +245,127 @@ class PostgresSqlDialect(SqlDialect, sqlglot_dialect="postgres"):
245
245
  WHEN 'I' THEN 'PARTITIONED INDEX'
246
246
  END as {column_alias}"""
247
247
 
248
- def build_columns_metadata_query_str(self, table_namespace: DataSourceNamespace, table_name: str) -> str:
249
- """
250
- Builds the full SQL query to query table names from the data source metadata.
251
- """
248
+ def _build_pg_columns_metadata_query(
249
+ self,
250
+ table_namespace: DataSourceNamespace,
251
+ table_name: str | None = None,
252
+ table_names: list[str] | None = None,
253
+ include_table_name_column: bool = False,
254
+ ) -> str:
255
+ """Shared pg_catalog-based column metadata query.
256
+ When table_name is provided, filters to that single table.
257
+ When table_names is provided, filters to those tables via IN clause.
258
+ When include_table_name_column is True, prepends relname to the SELECT columns."""
252
259
 
253
260
  database_name: str | None = table_namespace.get_database_for_metadata_query()
254
261
  schema_name: str = table_namespace.get_schema_for_metadata_query()
255
262
 
256
- ######
257
263
  current_database_expression = RAW_SQL(self._current_database())
258
- select: list = [
259
- SELECT(
260
- [
261
- COLUMN("attname", table_alias="a", field_alias="column_name"),
262
- # Normalize data type into information_schema.columns style. Consider doing this in python instead, but this is lightweight and simple enough.
263
- RAW_SQL(
264
- """CASE
265
- -- arrays
266
- WHEN t.typcategory = 'A' OR t.typelem <> 0 THEN 'ARRAY'
267
-
268
- -- choose base type for domains, otherwise the type itself
269
- ELSE CASE COALESCE(bt.typname, t.typname)
270
- WHEN 'varchar' THEN 'character varying'
271
- WHEN 'bpchar' THEN 'character'
272
- WHEN 'bool' THEN 'boolean'
273
- WHEN 'int2' THEN 'smallint'
274
- WHEN 'int4' THEN 'integer'
275
- WHEN 'int8' THEN 'bigint'
276
- WHEN 'float4' THEN 'real'
277
- WHEN 'float8' THEN 'double precision'
278
- WHEN 'timestamptz' THEN 'timestamp with time zone'
279
- WHEN 'timestamp' THEN 'timestamp without time zone'
280
- WHEN 'timetz' THEN 'time with time zone'
281
- WHEN 'time' THEN 'time without time zone'
282
- WHEN 'bit' THEN 'bit'
283
- WHEN 'varbit' THEN 'bit varying'
284
- ELSE COALESCE(bt.typname, t.typname)
264
+
265
+ select_columns = []
266
+ if include_table_name_column:
267
+ select_columns.append(COLUMN("relname", table_alias="c", field_alias="table_name"))
268
+
269
+ select_columns.extend(
270
+ [
271
+ COLUMN("attname", table_alias="a", field_alias="column_name"),
272
+ # Normalize data type into information_schema.columns style.
273
+ RAW_SQL(
274
+ """CASE
275
+ -- arrays
276
+ WHEN t.typcategory = 'A' OR t.typelem <> 0 THEN 'ARRAY'
277
+
278
+ -- choose base type for domains, otherwise the type itself
279
+ ELSE CASE COALESCE(bt.typname, t.typname)
280
+ WHEN 'varchar' THEN 'character varying'
281
+ WHEN 'bpchar' THEN 'character'
282
+ WHEN 'bool' THEN 'boolean'
283
+ WHEN 'int2' THEN 'smallint'
284
+ WHEN 'int4' THEN 'integer'
285
+ WHEN 'int8' THEN 'bigint'
286
+ WHEN 'float4' THEN 'real'
287
+ WHEN 'float8' THEN 'double precision'
288
+ WHEN 'timestamptz' THEN 'timestamp with time zone'
289
+ WHEN 'timestamp' THEN 'timestamp without time zone'
290
+ WHEN 'timetz' THEN 'time with time zone'
291
+ WHEN 'time' THEN 'time without time zone'
292
+ WHEN 'bit' THEN 'bit'
293
+ WHEN 'varbit' THEN 'bit varying'
294
+ ELSE COALESCE(bt.typname, t.typname)
295
+ END
296
+ END AS \"data_type\"
297
+ """
298
+ ),
299
+ # Extract type parameters. All a.atttypmod are offset by 4 in Postgres
300
+ # varchar/char length (NULL otherwise)
301
+ RAW_SQL(
302
+ """CASE
303
+ WHEN t.typname IN ('varchar','bpchar') THEN
304
+ CASE
305
+ WHEN a.atttypmod > 4 THEN a.atttypmod - 4
306
+ ELSE NULL
307
+ END
308
+ ELSE NULL
309
+ END AS "character_maximum_length"
310
+ """
311
+ ),
312
+ # numeric precision (NULL otherwise)
313
+ RAW_SQL(
314
+ """CASE
315
+ WHEN t.typname = 'numeric' THEN
316
+ CASE
317
+ WHEN a.atttypmod > 4 THEN ((a.atttypmod - 4) >> 16)
318
+ ELSE NULL
285
319
  END
286
- END AS \"data_type\"
287
- """
288
- ),
289
- # Extract type parameters. No abstract level api for this, we have to replicate Postgres logic here.
290
- # All a.atttypmod are offset by 4 in Postgres
291
- # varchar/char length (NULL otherwise)
292
- RAW_SQL(
293
- """CASE
294
- WHEN t.typname IN ('varchar','bpchar') THEN
295
- CASE
296
- WHEN a.atttypmod > 4 THEN a.atttypmod - 4
297
- ELSE NULL
298
- END
299
- ELSE NULL
300
- END AS "character_maximum_length"
301
- """
302
- ),
303
- # numeric precision (NULL otherwise)
304
- RAW_SQL(
305
- """CASE
306
- WHEN t.typname = 'numeric' THEN
307
- CASE
308
- WHEN a.atttypmod > 4 THEN ((a.atttypmod - 4) >> 16)
309
- ELSE NULL
310
- END
311
- ELSE NULL
312
- END AS "numeric_precision"
313
- """
314
- ),
315
- # numeric scale (NULL otherwise)
316
- RAW_SQL(
317
- """CASE
318
- WHEN t.typname = 'numeric' THEN
319
- CASE
320
- WHEN a.atttypmod > 4 THEN ((a.atttypmod - 4) & 65535)
321
- ELSE NULL
322
- END
323
- ELSE NULL
324
- END AS "numeric_scale"
325
- """
326
- ),
327
- # datetime precision (NULL otherwise)
328
- RAW_SQL(
329
- """CASE
330
- WHEN t.typname IN ('time','timetz','timestamp','timestamptz') THEN
331
- CASE
332
- WHEN a.atttypmod >= 0 THEN a.atttypmod
333
- ELSE NULL
334
- END
335
- ELSE NULL
336
- END AS "datetime_precision"
337
- """
338
- ),
339
- COLUMN(current_database_expression, field_alias="table_catalog"),
340
- COLUMN("nspname", table_alias="n", field_alias="table_schema"),
341
- COLUMN("relname", table_alias="c", field_alias="table_name"),
342
- RAW_SQL(self.relkind_table_type_sql_expression()),
343
- ]
320
+ ELSE NULL
321
+ END AS "numeric_precision"
322
+ """
323
+ ),
324
+ # numeric scale (NULL otherwise)
325
+ RAW_SQL(
326
+ """CASE
327
+ WHEN t.typname = 'numeric' THEN
328
+ CASE
329
+ WHEN a.atttypmod > 4 THEN ((a.atttypmod - 4) & 65535)
330
+ ELSE NULL
331
+ END
332
+ ELSE NULL
333
+ END AS "numeric_scale"
334
+ """
335
+ ),
336
+ # datetime precision (NULL otherwise)
337
+ RAW_SQL(
338
+ """CASE
339
+ WHEN t.typname IN ('time','timetz','timestamp','timestamptz') THEN
340
+ CASE
341
+ WHEN a.atttypmod >= 0 THEN a.atttypmod
342
+ ELSE NULL
343
+ END
344
+ ELSE NULL
345
+ END AS "datetime_precision"
346
+ """
347
+ ),
348
+ COLUMN(current_database_expression, field_alias="table_catalog"),
349
+ COLUMN("nspname", table_alias="n", field_alias="table_schema"),
350
+ COLUMN("relname", table_alias="c", field_alias="table_name"),
351
+ RAW_SQL(self.relkind_table_type_sql_expression()),
352
+ ]
353
+ )
354
+
355
+ where_conditions = [
356
+ IN(
357
+ COLUMN("relkind", "c"),
358
+ [LITERAL("r"), LITERAL("p"), LITERAL("v"), LITERAL("m"), LITERAL("f")],
344
359
  ),
360
+ GT(COLUMN("attnum", "a"), LITERAL(0)),
361
+ ]
362
+ if table_name:
363
+ where_conditions.append(EQ(COLUMN("relname", "c"), LITERAL(self.metadata_casify(table_name))))
364
+ elif table_names:
365
+ where_conditions.append(IN(COLUMN("relname", "c"), [LITERAL(self.metadata_casify(n)) for n in table_names]))
366
+
367
+ select: list = [
368
+ SELECT(select_columns),
345
369
  FROM(
346
370
  self._pg_class(),
347
371
  table_prefix=[self._pg_catalog()],
@@ -383,20 +407,7 @@ class PostgresSqlDialect(SqlDialect, sqlglot_dialect="postgres"):
383
407
  RAW_SQL("NULLIF(t.typbasetype, 0)"),
384
408
  ),
385
409
  ),
386
- WHERE(
387
- AND(
388
- [
389
- # Only get object types that correspond to tables/views in information_schema.tables
390
- IN(
391
- COLUMN("relkind", "c"),
392
- [LITERAL("r"), LITERAL("p"), LITERAL("v"), LITERAL("m"), LITERAL("f")],
393
- ),
394
- # Only get columns that are not dropped
395
- GT(COLUMN("attnum", "a"), LITERAL(0)),
396
- EQ(COLUMN("relname", "c"), LITERAL(self.metadata_casify(table_name))),
397
- ]
398
- )
399
- ),
410
+ WHERE(AND(where_conditions)),
400
411
  ORDER_BY_ASC(COLUMN("attnum", "a")),
401
412
  ]
402
413
 
@@ -408,3 +419,13 @@ class PostgresSqlDialect(SqlDialect, sqlglot_dialect="postgres"):
408
419
  select.append(WHERE(EQ(LOWER(COLUMN("nspname", "n")), LITERAL(schema_name.lower()))))
409
420
 
410
421
  return self.build_select_sql(select)
422
+
423
+ def build_columns_metadata_query_str(self, table_namespace: DataSourceNamespace, table_name: str) -> str:
424
+ return self._build_pg_columns_metadata_query(table_namespace, table_name=table_name)
425
+
426
+ def build_all_columns_metadata_query_str(
427
+ self, table_namespace: DataSourceNamespace, table_names: list[str] | None = None
428
+ ) -> str:
429
+ return self._build_pg_columns_metadata_query(
430
+ table_namespace, table_names=table_names, include_table_name_column=True
431
+ )
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: soda-postgres
3
- Version: 4.1.0
3
+ Version: 4.2.0
4
4
  Summary: Soda Postgres 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.1.0
8
+ Requires-Dist: soda-core==4.2.0
9
9
  Requires-Dist: psycopg[binary]>=3.2
@@ -1,2 +1,2 @@
1
- soda-core==4.1.0
1
+ soda-core==4.2.0
2
2
  psycopg[binary]>=3.2
File without changes