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.
- nl2data_semantic_catalog_postgres/__init__.py +18 -0
- nl2data_semantic_catalog_postgres/client.py +139 -0
- nl2data_semantic_catalog_postgres/config.py +136 -0
- nl2data_semantic_catalog_postgres/envelope.py +327 -0
- nl2data_semantic_catalog_postgres/errors.py +188 -0
- nl2data_semantic_catalog_postgres/fake_postgres/__init__.py +53 -0
- nl2data_semantic_catalog_postgres/fake_postgres/driver.py +209 -0
- nl2data_semantic_catalog_postgres/fake_postgres/handlers_audit.py +243 -0
- nl2data_semantic_catalog_postgres/fake_postgres/handlers_drafts.py +84 -0
- nl2data_semantic_catalog_postgres/fake_postgres/handlers_maintenance.py +263 -0
- nl2data_semantic_catalog_postgres/fake_postgres/handlers_publications.py +249 -0
- nl2data_semantic_catalog_postgres/fake_postgres/handlers_schema.py +23 -0
- nl2data_semantic_catalog_postgres/fake_postgres/handlers_snapshots.py +197 -0
- nl2data_semantic_catalog_postgres/fake_postgres/handlers_versions.py +330 -0
- nl2data_semantic_catalog_postgres/fake_postgres/keys.py +99 -0
- nl2data_semantic_catalog_postgres/fake_postgres/pool.py +152 -0
- nl2data_semantic_catalog_postgres/fake_postgres/registry.py +144 -0
- nl2data_semantic_catalog_postgres/maintenance.py +235 -0
- nl2data_semantic_catalog_postgres/py.typed +0 -0
- nl2data_semantic_catalog_postgres/repositories/__init__.py +26 -0
- nl2data_semantic_catalog_postgres/repositories/activation.py +849 -0
- nl2data_semantic_catalog_postgres/repositories/audit_evidence.py +221 -0
- nl2data_semantic_catalog_postgres/repositories/drafts.py +156 -0
- nl2data_semantic_catalog_postgres/repositories/evidence.py +415 -0
- nl2data_semantic_catalog_postgres/repositories/publications.py +486 -0
- nl2data_semantic_catalog_postgres/repositories/snapshots.py +372 -0
- nl2data_semantic_catalog_postgres/schema.py +337 -0
- nl2data_semantic_catalog_postgres/sql.py +520 -0
- nl2data_semantic_catalog_postgres/store.py +716 -0
- nl2data_semantic_catalog_postgres/unit_of_work.py +589 -0
- nl2data_semantic_catalog_postgres-0.1.0.dist-info/METADATA +76 -0
- nl2data_semantic_catalog_postgres-0.1.0.dist-info/RECORD +34 -0
- nl2data_semantic_catalog_postgres-0.1.0.dist-info/WHEEL +5 -0
- 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)
|