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.
- pgdevkit/db/complex_types.py +22 -4
- pgdevkit/testdb/schema.py +8 -3
- {pgdevkit-0.2.2.dist-info → pgdevkit-0.2.4.dist-info}/METADATA +1 -1
- {pgdevkit-0.2.2.dist-info → pgdevkit-0.2.4.dist-info}/RECORD +6 -6
- {pgdevkit-0.2.2.dist-info → pgdevkit-0.2.4.dist-info}/WHEEL +0 -0
- {pgdevkit-0.2.2.dist-info → pgdevkit-0.2.4.dist-info}/entry_points.txt +0 -0
pgdevkit/db/complex_types.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
186
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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):
|
|
@@ -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=
|
|
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
|
|
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.
|
|
29
|
-
pgdevkit-0.2.
|
|
30
|
-
pgdevkit-0.2.
|
|
31
|
-
pgdevkit-0.2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|