pgdevkit 0.2.2__py3-none-any.whl → 0.2.4__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.
@@ -9,7 +9,18 @@ from psycopg.types.composite import CompositeInfo, register_composite
9
9
  from psycopg.types.enum import EnumInfo, register_enum
10
10
  from psycopg.types.json import Jsonb
11
11
 
12
- ComplexTypeInfo = CompositeInfo | EnumInfo | type[Jsonb] | None
12
+
13
+ class JsonbArray:
14
+ """Sentinel for a `jsonb[]` column (a Postgres ARRAY of jsonb) — distinct
15
+ from `Jsonb` (a scalar jsonb column) so `recursive_convert` knows whether
16
+ an incoming Python list *is* the array (each element needs its own
17
+ `Jsonb(...)` wrapper) or is JSON array *content* for one scalar jsonb
18
+ value (the whole list gets wrapped once). Both cases arrive from
19
+ `information_schema.columns` looking identical (a plain Python list) —
20
+ only the column's own array-ness disambiguates them."""
21
+
22
+
23
+ ComplexTypeInfo = CompositeInfo | EnumInfo | type[Jsonb] | type[JsonbArray] | None
13
24
 
14
25
 
15
26
  class ComplexHelper:
@@ -67,7 +78,7 @@ class ComplexHelper:
67
78
  if res["data_type"].lower() == "jsonb":
68
79
  return Jsonb
69
80
  if res["data_type"].upper() == "ARRAY" and res["udt_name"] == "_jsonb":
70
- return Jsonb
81
+ return JsonbArray
71
82
  if (
72
83
  not res["is_enum"]
73
84
  and not res["is_user_defined"]
@@ -181,9 +192,16 @@ class ComplexHelper:
181
192
  return None
182
193
  if self.system_complex_type_dict is None:
183
194
  await self.load_complex_type_dict()
195
+ if info == JsonbArray:
196
+ # The value here *is* the jsonb[] array -- each element is its
197
+ # own scalar jsonb value, unlike the plain-Jsonb case below.
198
+ assert isinstance(value, list), f"Expected a list for a jsonb[] column, got {type(value)}"
199
+ return [Jsonb(item) for item in value]
184
200
  if info == Jsonb:
185
- # A JSONB column's value is wrapped whole, even if it's a list —
186
- # only an array-of-composite/enum column recurses per element.
201
+ # A scalar JSONB column's value is wrapped whole, even if it's a
202
+ # list — that list is JSON array *content* for the one jsonb
203
+ # value, not multiple array elements (see JsonbArray above for
204
+ # the jsonb[] column case).
187
205
  return Jsonb(value)
188
206
  if isinstance(value, list):
189
207
  return [await self.recursive_convert(item, info, con) for item in value]
pgdevkit/testdb/schema.py CHANGED
@@ -94,7 +94,11 @@ def _get_sql_deps(sql: str) -> set[str]:
94
94
  continue
95
95
  for t in e.find_all(exp.Table):
96
96
  if t.args.get("this") is not None and t.args.get("db") is not None:
97
- deps.add(str(t))
97
+ # exp.table_name(), not str(t): str() includes " AS alias" for
98
+ # an aliased reference (e.g. "FROM editing.visit v"), which
99
+ # would never match the plain declared name any dependent
100
+ # file's own CREATE target is recorded under.
101
+ deps.add(exp.table_name(t))
98
102
  return deps
99
103
 
100
104
 
@@ -119,7 +123,7 @@ def _iter_sql_files(database_dir: Path):
119
123
  deps = _get_sql_deps(content)
120
124
  if file.parent.name in _SCHEMA_QUALIFIED_TYPES:
121
125
  schema = _strip_layer_prefix(file.parent.parent.name)
122
- full_name = f"{schema}.{file.stem}"
126
+ full_name = f"{schema}.{_strip_layer_prefix(file.stem)}"
123
127
  deps.discard(full_name) # the file's own CREATE target is not a real dependency
124
128
  all_declared.add(full_name)
125
129
  if not deps or all(d in delivered for d in deps):
@@ -219,7 +223,8 @@ async def apply_schema(
219
223
  json_file = file.with_suffix(".test_data.json")
220
224
  if json_file.exists():
221
225
  schema_name = _strip_layer_prefix(file.parent.parent.name)
222
- await _insert_test_data(json_file, f"{schema_name}.{file.stem}", force_reset, con, complex_helper)
226
+ table_stem = _strip_layer_prefix(file.stem)
227
+ await _insert_test_data(json_file, f"{schema_name}.{table_stem}", force_reset, con, complex_helper)
223
228
 
224
229
  failures: list[tuple[Path, str]] = []
225
230
  for file, sql in _iter_sql_files(database_dir):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgdevkit
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: A helper for developing with Postgres
5
5
  Requires-Python: >=3.14
6
6
  Requires-Dist: docker>=7.1.0
@@ -8,7 +8,7 @@ pgdevkit/lakebase.py,sha256=0PABOk4p-2klLTY8QAUibQf9QeyNHKywUWEWGdkUY8k,3165
8
8
  pgdevkit/models.py,sha256=dAZ8f7pgDsxoLVrDWsM4h0qwJ0pOzXDdWMGsnjrW80E,2103
9
9
  pgdevkit/parser.py,sha256=B3NRtcSBuEUcQNp5lxEMi6ApVedkbNUNdklCea-Ts40,12021
10
10
  pgdevkit/db/__init__.py,sha256=PlnMycSmQVqnzHue_uLQZuikbW6QAqs6p91IO5l6nfU,763
11
- pgdevkit/db/complex_types.py,sha256=t1y5_yIGLUtI_iuBUr7Es7e83OD9YVyvzInwLyaMfcM,10197
11
+ pgdevkit/db/complex_types.py,sha256=bv3oMztSnrhz4-OJROBXfiouL2jJ8TxpSR_83HMLmTI,11197
12
12
  pgdevkit/db/connection.py,sha256=ylc_KVYsOvPeuW5GL1ebDDH0O3w93oe-EHwkUH4KoVs,5793
13
13
  pgdevkit/db/crud.py,sha256=RTRhum5GyfeRAw8p8kk_kFr9uKCeWe8wwrUZYLvzdZU,12103
14
14
  pgdevkit/db/loader.py,sha256=0Swmp0h0s7I4acG0Dv3cem2YD4lFvq8aFEbFQPPQrxg,616
@@ -20,12 +20,12 @@ pgdevkit/testdb/constants.py,sha256=xi8uIoEgN9LrRkr41j3mmWB9PqqU0r8aCUb2JJXBAs0,
20
20
  pgdevkit/testdb/container.py,sha256=R_IhazRw_c0HteDtESO6RY6XWHp995FP5RRA4LK7Fh0,4068
21
21
  pgdevkit/testdb/naming.py,sha256=Kyk5qEfxUkbggUG5bD7U7CJ_kAET332VPQNB-O5kvTY,1318
22
22
  pgdevkit/testdb/query.py,sha256=e4UbgdCKKIot3a8Qixg-OX-Af0rlQ4a8ODhJBD8mtVM,2318
23
- pgdevkit/testdb/schema.py,sha256=-whDO8JTggFPNZtymzQ7dpsqMdQ-wUYAlRdWuyT4CAQ,9590
23
+ pgdevkit/testdb/schema.py,sha256=CpKee72evg9dngo744VXcbn8YHTq5AQIY0xgF-6eMkU,9970
24
24
  pgdevkit/docs/database-layout.md,sha256=dNvDH956xSXuAnLqkOopyOfaIm_A-RtUd57VTaZ1GQU,6035
25
25
  pgdevkit/skills/pgdevkit/SKILL.md,sha256=6uxe6BQwOLexGiBpf00VTFTHOiWJo5k2Qqzu172rb4I,12156
26
26
  pgdevkit/skills/pgdevkit/references/dynamic-sql.md,sha256=aTR1sx81moiTwaMaiOecaqk-9rT8y5Zxz7W1BoC3vK0,2774
27
27
  pgdevkit/skills/pgdevkit/references/temporal-tables.md,sha256=LwZnItvQWI7bB0oRHxIfUc0ynnq7N0V5Mnv-QHvFN3Q,1364
28
- pgdevkit-0.2.2.dist-info/METADATA,sha256=56tCcCKLAnudYqguZtBn60RMnmGmKt-sk0yeFEG-y8c,5915
29
- pgdevkit-0.2.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
30
- pgdevkit-0.2.2.dist-info/entry_points.txt,sha256=FK2P55lf0WaGlOZJIINOGgCt8WB7ep0OnPsgnrp80bg,42
31
- pgdevkit-0.2.2.dist-info/RECORD,,
28
+ pgdevkit-0.2.4.dist-info/METADATA,sha256=vM_8DEMsPyq7CSplDGBhDdWpPJLD_wrMNJk4GSvWRVA,5915
29
+ pgdevkit-0.2.4.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
30
+ pgdevkit-0.2.4.dist-info/entry_points.txt,sha256=FK2P55lf0WaGlOZJIINOGgCt8WB7ep0OnPsgnrp80bg,42
31
+ pgdevkit-0.2.4.dist-info/RECORD,,