nl2data-semantic-catalog-postgres 0.1.0__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.
Files changed (34) hide show
  1. nl2data_semantic_catalog_postgres/__init__.py +18 -0
  2. nl2data_semantic_catalog_postgres/client.py +139 -0
  3. nl2data_semantic_catalog_postgres/config.py +136 -0
  4. nl2data_semantic_catalog_postgres/envelope.py +327 -0
  5. nl2data_semantic_catalog_postgres/errors.py +188 -0
  6. nl2data_semantic_catalog_postgres/fake_postgres/__init__.py +53 -0
  7. nl2data_semantic_catalog_postgres/fake_postgres/driver.py +209 -0
  8. nl2data_semantic_catalog_postgres/fake_postgres/handlers_audit.py +243 -0
  9. nl2data_semantic_catalog_postgres/fake_postgres/handlers_drafts.py +84 -0
  10. nl2data_semantic_catalog_postgres/fake_postgres/handlers_maintenance.py +263 -0
  11. nl2data_semantic_catalog_postgres/fake_postgres/handlers_publications.py +249 -0
  12. nl2data_semantic_catalog_postgres/fake_postgres/handlers_schema.py +23 -0
  13. nl2data_semantic_catalog_postgres/fake_postgres/handlers_snapshots.py +197 -0
  14. nl2data_semantic_catalog_postgres/fake_postgres/handlers_versions.py +330 -0
  15. nl2data_semantic_catalog_postgres/fake_postgres/keys.py +99 -0
  16. nl2data_semantic_catalog_postgres/fake_postgres/pool.py +152 -0
  17. nl2data_semantic_catalog_postgres/fake_postgres/registry.py +144 -0
  18. nl2data_semantic_catalog_postgres/maintenance.py +235 -0
  19. nl2data_semantic_catalog_postgres/py.typed +0 -0
  20. nl2data_semantic_catalog_postgres/repositories/__init__.py +26 -0
  21. nl2data_semantic_catalog_postgres/repositories/activation.py +849 -0
  22. nl2data_semantic_catalog_postgres/repositories/audit_evidence.py +221 -0
  23. nl2data_semantic_catalog_postgres/repositories/drafts.py +156 -0
  24. nl2data_semantic_catalog_postgres/repositories/evidence.py +415 -0
  25. nl2data_semantic_catalog_postgres/repositories/publications.py +486 -0
  26. nl2data_semantic_catalog_postgres/repositories/snapshots.py +372 -0
  27. nl2data_semantic_catalog_postgres/schema.py +337 -0
  28. nl2data_semantic_catalog_postgres/sql.py +520 -0
  29. nl2data_semantic_catalog_postgres/store.py +716 -0
  30. nl2data_semantic_catalog_postgres/unit_of_work.py +589 -0
  31. nl2data_semantic_catalog_postgres-0.1.0.dist-info/METADATA +76 -0
  32. nl2data_semantic_catalog_postgres-0.1.0.dist-info/RECORD +34 -0
  33. nl2data_semantic_catalog_postgres-0.1.0.dist-info/WHEEL +5 -0
  34. nl2data_semantic_catalog_postgres-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,197 @@
1
+ """Snapshot, snapshot-pointer, and proposal-set statement handlers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from .driver import _as_dt
8
+ from .keys import _lock_or_fail, _pointer_key, _proposal_key, _snap_key
9
+
10
+ if TYPE_CHECKING:
11
+ from .driver import _FakeConnection
12
+ from .pool import FakePostgresPool
13
+
14
+
15
+ def _h_upsert_snapshot(
16
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
17
+ ) -> tuple[list[dict[str, Any]], int]:
18
+ namespace, fingerprint = params[0], params[1]
19
+ key = _snap_key(namespace, fingerprint)
20
+ _lock_or_fail(pool, conn, key, timeout)
21
+ row = pool.snapshots.get((namespace, fingerprint))
22
+ conn._touch(key)
23
+ if row is None:
24
+ pool.snapshots[(namespace, fingerprint)] = {
25
+ "scope_namespace": namespace,
26
+ "snapshot_fingerprint": fingerprint,
27
+ "source_id": params[2],
28
+ "state": params[3],
29
+ "schema_version": params[4],
30
+ "envelope": params[5],
31
+ "discovered_at": _as_dt(params[6]),
32
+ "retained_until": _as_dt(params[7]),
33
+ "activated_at": None,
34
+ "created_at": _as_dt(params[8]),
35
+ }
36
+ else:
37
+ # Mirrors ON CONFLICT DO UPDATE: state/created_at are preserved.
38
+ row.update(
39
+ source_id=params[2],
40
+ schema_version=params[4],
41
+ envelope=params[5],
42
+ discovered_at=_as_dt(params[6]),
43
+ retained_until=_as_dt(params[7]),
44
+ )
45
+ return ([], 1)
46
+
47
+
48
+ def _h_read_snapshot_envelope(
49
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
50
+ ) -> tuple[list[dict[str, Any]], int]:
51
+ row = pool.snapshots.get((params[0], params[1]))
52
+ if row is None:
53
+ return ([], 0)
54
+ return (
55
+ [
56
+ {
57
+ "envelope": row["envelope"],
58
+ "schema_version": row["schema_version"],
59
+ "discovered_at": row["discovered_at"],
60
+ }
61
+ ],
62
+ 0,
63
+ )
64
+
65
+
66
+ def _h_lock_snapshot_row(
67
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
68
+ ) -> tuple[list[dict[str, Any]], int]:
69
+ row = pool.snapshots.get((params[0], params[1]))
70
+ if row is None:
71
+ return ([], 0)
72
+ _lock_or_fail(pool, conn, _snap_key(params[0], params[1]), timeout)
73
+ return (
74
+ [
75
+ {
76
+ "source_id": row["source_id"],
77
+ "state": row["state"],
78
+ "retained_until": row["retained_until"],
79
+ "discovered_at": row["discovered_at"],
80
+ "envelope": row["envelope"],
81
+ "schema_version": row["schema_version"],
82
+ }
83
+ ],
84
+ 0,
85
+ )
86
+
87
+
88
+ def _h_set_snapshot_state(
89
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
90
+ ) -> tuple[list[dict[str, Any]], int]:
91
+ namespace, fingerprint = params[2], params[3]
92
+ key = _snap_key(namespace, fingerprint)
93
+ _lock_or_fail(pool, conn, key, timeout)
94
+ row = pool.snapshots.get((namespace, fingerprint))
95
+ if row is None:
96
+ return ([], 0)
97
+ conn._touch(key)
98
+ row.update(state=params[0], activated_at=_as_dt(params[1]))
99
+ return ([], 1)
100
+
101
+
102
+ def _h_snapshot_exists(
103
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
104
+ ) -> tuple[list[dict[str, Any]], int]:
105
+ if (params[0], params[1]) in pool.snapshots:
106
+ return ([{"exists": True}], 0)
107
+ return ([], 0)
108
+
109
+
110
+ def _h_upsert_snapshot_pointer(
111
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
112
+ ) -> tuple[list[dict[str, Any]], int]:
113
+ namespace, source_id = params[0], params[1]
114
+ key = _pointer_key(namespace, source_id)
115
+ _lock_or_fail(pool, conn, key, timeout)
116
+ row = pool.snapshot_pointers.get((namespace, source_id))
117
+ conn._touch(key)
118
+ if row is None:
119
+ pool.snapshot_pointers[(namespace, source_id)] = {
120
+ "scope_namespace": namespace,
121
+ "source_id": source_id,
122
+ "snapshot_fingerprint": params[2],
123
+ "schema_version": params[3],
124
+ "activated_at": _as_dt(params[4]),
125
+ }
126
+ else:
127
+ row.update(
128
+ snapshot_fingerprint=params[2],
129
+ schema_version=params[3],
130
+ activated_at=_as_dt(params[4]),
131
+ )
132
+ return ([], 1)
133
+
134
+
135
+ def _h_read_snapshot_pointer(
136
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
137
+ ) -> tuple[list[dict[str, Any]], int]:
138
+ row = pool.snapshot_pointers.get((params[0], params[1]))
139
+ if row is None:
140
+ return ([], 0)
141
+ return (
142
+ [
143
+ {
144
+ "snapshot_fingerprint": row["snapshot_fingerprint"],
145
+ "schema_version": row["schema_version"],
146
+ }
147
+ ],
148
+ 0,
149
+ )
150
+
151
+
152
+ def _h_list_snapshot_pointers(
153
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
154
+ ) -> tuple[list[dict[str, Any]], int]:
155
+ rows = [
156
+ {
157
+ "scope_namespace": namespace,
158
+ "source_id": source_id,
159
+ "snapshot_fingerprint": row["snapshot_fingerprint"],
160
+ }
161
+ for (namespace, source_id), row in sorted(pool.snapshot_pointers.items())
162
+ ]
163
+ return (rows, len(rows))
164
+
165
+
166
+ def _h_upsert_proposal_set(
167
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
168
+ ) -> tuple[list[dict[str, Any]], int]:
169
+ namespace, fingerprint = params[0], params[1]
170
+ key = _proposal_key(namespace, fingerprint)
171
+ _lock_or_fail(pool, conn, key, timeout)
172
+ row = pool.proposal_sets.get((namespace, fingerprint))
173
+ conn._touch(key)
174
+ if row is None:
175
+ pool.proposal_sets[(namespace, fingerprint)] = {
176
+ "scope_namespace": namespace,
177
+ "snapshot_fingerprint": fingerprint,
178
+ "schema_version": params[2],
179
+ "envelope": params[3],
180
+ "saved_at": _as_dt(params[4]),
181
+ }
182
+ else:
183
+ row.update(
184
+ schema_version=params[2],
185
+ envelope=params[3],
186
+ saved_at=_as_dt(params[4]),
187
+ )
188
+ return ([], 1)
189
+
190
+
191
+ def _h_read_proposal_set(
192
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
193
+ ) -> tuple[list[dict[str, Any]], int]:
194
+ row = pool.proposal_sets.get((params[0], params[1]))
195
+ if row is None:
196
+ return ([], 0)
197
+ return ([{"envelope": row["envelope"], "schema_version": row["schema_version"]}], 0)
@@ -0,0 +1,330 @@
1
+ """Published-version, supersession, pointer, and history statement handlers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from .driver import UniqueViolation, _as_dt
8
+ from .keys import (
9
+ _bundle_pointer_key,
10
+ _history_key,
11
+ _lock_or_fail,
12
+ _supersession_key,
13
+ _version_key,
14
+ )
15
+
16
+ if TYPE_CHECKING:
17
+ from .driver import _FakeConnection
18
+ from .pool import FakePostgresPool
19
+
20
+
21
+ def _h_read_latest_version(
22
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
23
+ ) -> tuple[list[dict[str, Any]], int]:
24
+ namespace, bundle_id = params
25
+ candidates = [
26
+ row
27
+ for (scope, candidate_id, _fingerprint), row in pool.published_versions.items()
28
+ if scope == namespace and candidate_id == bundle_id
29
+ ]
30
+ if not candidates:
31
+ return ([], 0)
32
+ row = max(candidates, key=lambda item: (item["published_at"], item["model_version"]))
33
+ _lock_or_fail(
34
+ pool,
35
+ conn,
36
+ _version_key(namespace, bundle_id, row["bundle_fingerprint"]),
37
+ timeout,
38
+ )
39
+ return ([{
40
+ "bundle_fingerprint": row["bundle_fingerprint"],
41
+ "lifecycle_state": row["lifecycle_state"],
42
+ }], 0)
43
+
44
+
45
+ def _h_insert_published_version(
46
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
47
+ ) -> tuple[list[dict[str, Any]], int]:
48
+ key = _version_key(params[0], params[1], params[2])
49
+ _lock_or_fail(pool, conn, key, timeout)
50
+ if key[1:] in pool.published_versions or any(
51
+ scope == params[0]
52
+ and bundle_id == params[1]
53
+ and row["model_version"] == params[3]
54
+ for (scope, bundle_id, _fingerprint), row in pool.published_versions.items()
55
+ ):
56
+ raise UniqueViolation("published version already exists")
57
+ conn._touch(key)
58
+ pool.published_versions[key[1:]] = {
59
+ "scope_namespace": params[0],
60
+ "bundle_id": params[1],
61
+ "bundle_fingerprint": params[2],
62
+ "model_version": params[3],
63
+ "lifecycle_state": params[4],
64
+ "predecessor_fingerprint": params[5],
65
+ "successor_fingerprint": params[6],
66
+ "audit_id": params[7],
67
+ "published_at": _as_dt(params[8]),
68
+ }
69
+ return ([], 1)
70
+
71
+
72
+ def _h_update_version_successor(
73
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
74
+ ) -> tuple[list[dict[str, Any]], int]:
75
+ successor, namespace, bundle_id, fingerprint = params
76
+ key = _version_key(namespace, bundle_id, fingerprint)
77
+ _lock_or_fail(pool, conn, key, timeout)
78
+ row = pool.published_versions.get(key[1:])
79
+ if row is None:
80
+ return ([], 0)
81
+ conn._touch(key)
82
+ row["successor_fingerprint"] = successor
83
+ if row["lifecycle_state"] != "active":
84
+ row["lifecycle_state"] = "superseded"
85
+ return ([], 1)
86
+
87
+
88
+ def _h_insert_supersession_edge(
89
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
90
+ ) -> tuple[list[dict[str, Any]], int]:
91
+ key = _supersession_key(params[0], params[1], params[3])
92
+ _lock_or_fail(pool, conn, key, timeout)
93
+ if key[1:] in pool.supersession_edges:
94
+ raise UniqueViolation("supersession edge already exists")
95
+ conn._touch(key)
96
+ pool.supersession_edges[key[1:]] = {
97
+ "scope_namespace": params[0],
98
+ "bundle_id": params[1],
99
+ "predecessor_fingerprint": params[2],
100
+ "successor_fingerprint": params[3],
101
+ "created_at": _as_dt(params[4]),
102
+ }
103
+ return ([], 1)
104
+
105
+
106
+ def _h_read_published_version(
107
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
108
+ ) -> tuple[list[dict[str, Any]], int]:
109
+ row = pool.published_versions.get(params)
110
+ if row is None:
111
+ return ([], 0)
112
+ return ([dict(row)], 0)
113
+
114
+
115
+ def _h_list_published_versions(
116
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
117
+ ) -> tuple[list[dict[str, Any]], int]:
118
+ namespace, bundle_id = params
119
+ rows = [
120
+ dict(row)
121
+ for (scope, candidate_id, _fingerprint), row in pool.published_versions.items()
122
+ if scope == namespace and candidate_id == bundle_id
123
+ ]
124
+ rows.sort(key=lambda row: (row["published_at"], row["model_version"]))
125
+ return (rows, len(rows))
126
+
127
+
128
+ def _h_set_published_version_state(
129
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
130
+ ) -> tuple[list[dict[str, Any]], int]:
131
+ state, namespace, bundle_id, fingerprint = params
132
+ key = _version_key(namespace, bundle_id, fingerprint)
133
+ _lock_or_fail(pool, conn, key, timeout)
134
+ row = pool.published_versions.get(key[1:])
135
+ if row is None:
136
+ return ([], 0)
137
+ conn._touch(key)
138
+ row["lifecycle_state"] = state
139
+ return ([], 1)
140
+
141
+
142
+ def _h_upsert_bundle_pointer(
143
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
144
+ ) -> tuple[list[dict[str, Any]], int]:
145
+ namespace, bundle_id = params[0], params[1]
146
+ key = _bundle_pointer_key(namespace, bundle_id)
147
+ _lock_or_fail(pool, conn, key, timeout)
148
+ row = pool.bundle_pointers.get((namespace, bundle_id))
149
+ conn._touch(key)
150
+ if row is None:
151
+ pool.bundle_pointers[(namespace, bundle_id)] = {
152
+ "scope_namespace": namespace,
153
+ "bundle_id": bundle_id,
154
+ "model_version": params[2],
155
+ "bundle_fingerprint": params[3],
156
+ "schema_version": params[4],
157
+ "activated_at": _as_dt(params[5]),
158
+ "activation_sequence": params[6],
159
+ }
160
+ else:
161
+ row.update(
162
+ model_version=params[2],
163
+ bundle_fingerprint=params[3],
164
+ schema_version=params[4],
165
+ activated_at=_as_dt(params[5]),
166
+ activation_sequence=params[6],
167
+ )
168
+ return ([], 1)
169
+
170
+
171
+ def _h_read_bundle_pointer(
172
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
173
+ ) -> tuple[list[dict[str, Any]], int]:
174
+ row = pool.bundle_pointers.get((params[0], params[1]))
175
+ if row is None:
176
+ return ([], 0)
177
+ return (
178
+ [
179
+ {
180
+ "model_version": row["model_version"],
181
+ "bundle_fingerprint": row["bundle_fingerprint"],
182
+ "schema_version": row["schema_version"],
183
+ "activation_sequence": row["activation_sequence"],
184
+ }
185
+ ],
186
+ 0,
187
+ )
188
+
189
+
190
+ def _h_lock_bundle_pointer(
191
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
192
+ ) -> tuple[list[dict[str, Any]], int]:
193
+ row = pool.bundle_pointers.get((params[0], params[1]))
194
+ if row is None:
195
+ return ([], 0)
196
+ _lock_or_fail(pool, conn, _bundle_pointer_key(params[0], params[1]), timeout)
197
+ return (
198
+ [
199
+ {
200
+ "model_version": row["model_version"],
201
+ "bundle_fingerprint": row["bundle_fingerprint"],
202
+ "schema_version": row["schema_version"],
203
+ "activation_sequence": row["activation_sequence"],
204
+ "activated_at": row["activated_at"],
205
+ }
206
+ ],
207
+ 0,
208
+ )
209
+
210
+
211
+ def _h_next_history_position(
212
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
213
+ ) -> tuple[list[dict[str, Any]], int]:
214
+ history = pool.bundle_history.get((params[0], params[1]), {})
215
+ next_position = (max(history) if history else 0) + 1
216
+ return ([{"next_position": next_position}], 0)
217
+
218
+
219
+ def _h_insert_history(
220
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
221
+ ) -> tuple[list[dict[str, Any]], int]:
222
+ namespace, bundle_id = params[0], params[1]
223
+ key = _history_key(namespace, bundle_id)
224
+ _lock_or_fail(pool, conn, key, timeout)
225
+ conn._touch(key)
226
+ history = pool.bundle_history.setdefault((namespace, bundle_id), {})
227
+ history[params[2]] = {
228
+ "scope_namespace": namespace,
229
+ "bundle_id": bundle_id,
230
+ "position": params[2],
231
+ "model_version": params[3],
232
+ "bundle_fingerprint": params[4],
233
+ "schema_version": params[5],
234
+ "activated_at": _as_dt(params[6]),
235
+ "deactivated_at": _as_dt(params[7]),
236
+ }
237
+ return ([], 1)
238
+
239
+
240
+ def _h_read_history_top(
241
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
242
+ ) -> tuple[list[dict[str, Any]], int]:
243
+ history = pool.bundle_history.get((params[0], params[1]), {})
244
+ if not history:
245
+ return ([], 0)
246
+ position = max(history)
247
+ row = history[position]
248
+ return (
249
+ [
250
+ {
251
+ "position": row["position"],
252
+ "model_version": row["model_version"],
253
+ "bundle_fingerprint": row["bundle_fingerprint"],
254
+ "schema_version": row["schema_version"],
255
+ "activated_at": row["activated_at"],
256
+ }
257
+ ],
258
+ 0,
259
+ )
260
+
261
+
262
+ def _h_delete_history_top(
263
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
264
+ ) -> tuple[list[dict[str, Any]], int]:
265
+ namespace, bundle_id, position = params[0], params[1], params[2]
266
+ key = _history_key(namespace, bundle_id)
267
+ _lock_or_fail(pool, conn, key, timeout)
268
+ history = pool.bundle_history.get((namespace, bundle_id))
269
+ if history is None or position not in history:
270
+ return ([], 0)
271
+ conn._touch(key)
272
+ del history[position]
273
+ if not history:
274
+ del pool.bundle_history[(namespace, bundle_id)]
275
+ return ([], 1)
276
+
277
+
278
+ def _h_trim_history(
279
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
280
+ ) -> tuple[list[dict[str, Any]], int]:
281
+ namespace, bundle_id = params[0], params[1]
282
+ trim_below = params[2]
283
+ key = _history_key(namespace, bundle_id)
284
+ _lock_or_fail(pool, conn, key, timeout)
285
+ history = pool.bundle_history.get((namespace, bundle_id))
286
+ if not history:
287
+ return ([], 0)
288
+ conn._touch(key)
289
+ removed = sum(
290
+ 1 for position in list(history) if position < trim_below
291
+ )
292
+ for position in list(history):
293
+ if position < trim_below:
294
+ del history[position]
295
+ if not history:
296
+ del pool.bundle_history[(namespace, bundle_id)]
297
+ return ([], removed)
298
+
299
+
300
+ def _h_list_bundle_pointers(
301
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
302
+ ) -> tuple[list[dict[str, Any]], int]:
303
+ rows = [
304
+ {
305
+ "scope_namespace": namespace,
306
+ "bundle_id": bundle_id,
307
+ "model_version": row["model_version"],
308
+ "bundle_fingerprint": row["bundle_fingerprint"],
309
+ }
310
+ for (namespace, bundle_id), row in sorted(pool.bundle_pointers.items())
311
+ ]
312
+ return (rows, len(rows))
313
+
314
+
315
+ def _h_list_orphan_active_versions(
316
+ pool: FakePostgresPool, conn: _FakeConnection, params: tuple[Any, ...], timeout: float
317
+ ) -> tuple[list[dict[str, Any]], int]:
318
+ rows = [
319
+ {
320
+ "scope_namespace": scope,
321
+ "bundle_id": bundle_id,
322
+ "model_version": row["model_version"],
323
+ }
324
+ for (scope, bundle_id, _fingerprint), row in sorted(
325
+ pool.published_versions.items()
326
+ )
327
+ if row["lifecycle_state"] == "active"
328
+ and (scope, bundle_id) not in pool.bundle_pointers
329
+ ]
330
+ return (rows, len(rows))
@@ -0,0 +1,99 @@
1
+ """Fake-pool table registry, row-key construction, and lock helpers.
2
+
3
+ Tables are keyed by ``(namespace, fingerprint)`` / ``(namespace, id)``
4
+ tuples (three-part keys for publications) so tenant-scoped and unscoped
5
+ records stay isolated exactly as the real schema enforces. Handlers lock
6
+ a key slot before checking existence so concurrent writers serialize like
7
+ the real unique indexes.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ if TYPE_CHECKING:
15
+ from .driver import _FakeConnection
16
+ from .pool import FakePostgresPool
17
+
18
+
19
+ def _snap_key(namespace: str, fingerprint: str) -> tuple[Any, ...]:
20
+ return ("snapshots", namespace, fingerprint)
21
+
22
+
23
+ def _pointer_key(namespace: str, source_id: str) -> tuple[Any, ...]:
24
+ return ("snapshot_pointers", namespace, source_id)
25
+
26
+
27
+ def _proposal_key(namespace: str, fingerprint: str) -> tuple[Any, ...]:
28
+ return ("proposal_sets", namespace, fingerprint)
29
+
30
+
31
+ def _draft_key(namespace: str, draft_id: str) -> tuple[Any, ...]:
32
+ return ("assembly_drafts", namespace, draft_id)
33
+
34
+
35
+ def _publication_key(
36
+ namespace: str, bundle_id: str, version: str
37
+ ) -> tuple[Any, ...]:
38
+ return ("publications", namespace, bundle_id, version)
39
+
40
+
41
+ def _manifest_key(
42
+ namespace: str, bundle_id: str, fingerprint: str
43
+ ) -> tuple[Any, ...]:
44
+ return ("accepted_manifests", namespace, bundle_id, fingerprint)
45
+
46
+
47
+ def _verification_evidence_key(
48
+ namespace: str, bundle_id: str, fingerprint: str
49
+ ) -> tuple[Any, ...]:
50
+ return ("verification_evidence", namespace, bundle_id, fingerprint)
51
+
52
+
53
+ def _audit_key(
54
+ namespace: str, bundle_id: str, fingerprint: str
55
+ ) -> tuple[Any, ...]:
56
+ return ("publish_audits", namespace, bundle_id, fingerprint)
57
+
58
+
59
+ def _version_key(
60
+ namespace: str, bundle_id: str, fingerprint: str
61
+ ) -> tuple[Any, ...]:
62
+ return ("published_versions", namespace, bundle_id, fingerprint)
63
+
64
+
65
+ def _supersession_key(
66
+ namespace: str, bundle_id: str, successor: str
67
+ ) -> tuple[Any, ...]:
68
+ return ("supersession_edges", namespace, bundle_id, successor)
69
+
70
+
71
+ def _bundle_pointer_key(namespace: str, bundle_id: str) -> tuple[Any, ...]:
72
+ return ("bundle_pointers", namespace, bundle_id)
73
+
74
+
75
+ def _history_key(namespace: str, bundle_id: str) -> tuple[Any, ...]:
76
+ return ("bundle_history", namespace, bundle_id)
77
+
78
+
79
+ def _event_key(namespace: str, event_id: str) -> tuple[Any, ...]:
80
+ return ("events", namespace, event_id)
81
+
82
+
83
+ def _publication_audit_evidence_key(
84
+ namespace: str, bundle_id: str, fingerprint: str
85
+ ) -> tuple[Any, ...]:
86
+ return ("publication_audit_evidence", namespace, bundle_id, fingerprint)
87
+
88
+
89
+ def _audit_entry_key(namespace: str, event_id: str) -> tuple[Any, ...]:
90
+ return ("audit_entries", namespace, event_id)
91
+
92
+
93
+ def _lock_or_fail(
94
+ pool: FakePostgresPool,
95
+ connection: _FakeConnection,
96
+ key: tuple[Any, ...],
97
+ timeout: float,
98
+ ) -> None:
99
+ pool._lock(connection, key, timeout)