lorebase-store 0.2.3__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.
- lorebase_store/__init__.py +1 -0
- lorebase_store/_migrations/env.py +106 -0
- lorebase_store/_migrations/script.py.mako +27 -0
- lorebase_store/_migrations/versions/0001_initial_schema.py +1071 -0
- lorebase_store/_migrations/versions/0002_merge_attempt_details.py +74 -0
- lorebase_store/_migrations/versions/0003_webhooks.py +127 -0
- lorebase_store/_migrations/versions/0004_defer_revision_references.py +38 -0
- lorebase_store/_migrations/versions/0005_security_definer_reads.py +396 -0
- lorebase_store/_migrations/versions/0006_api_key_usage.py +48 -0
- lorebase_store/_migrations/versions/0007_document_extraction.py +154 -0
- lorebase_store/_migrations/versions/0008_definer_argument_checks.py +178 -0
- lorebase_store/_migrations/versions/0009_api_key_networks.py +33 -0
- lorebase_store/_migrations/versions/0010_overlay_branches.py +582 -0
- lorebase_store/_migrations/versions/0011_branch_scoped_search_index.py +229 -0
- lorebase_store/_migrations/versions/0012_overlay_neighborhood_lookups.py +185 -0
- lorebase_store/_migrations/versions/0013_web_sessions.py +72 -0
- lorebase_store/_migrations/versions/0014_embedding_jobs.py +70 -0
- lorebase_store/_migrations/versions/0015_append_only_audit_log.py +83 -0
- lorebase_store/_migrations/versions/0016_sealed_webhook_keys.py +55 -0
- lorebase_store/_migrations/versions/0017_background_branch_copies.py +77 -0
- lorebase_store/_migrations/versions/0018_search_lexicon.py +477 -0
- lorebase_store/_migrations/versions/0019_vault_bindings.py +56 -0
- lorebase_store/_migrations/versions/0020_outbox_consumers.py +150 -0
- lorebase_store/_migrations/versions/0021_schema_suggestions.py +114 -0
- lorebase_store/_migrations/versions/0022_read_audit_and_shared_rate_limits.py +133 -0
- lorebase_store/_migrations/versions/0023_agent_trace.py +96 -0
- lorebase_store/_migrations/versions/0024_embedding_template_keys.py +205 -0
- lorebase_store/_migrations/versions/0025_snapshot_refs.py +35 -0
- lorebase_store/_migrations/versions/0026_plain_reverse_link_index.py +112 -0
- lorebase_store/_migrations/versions/0027_vault_rotation_and_tombstones.py +145 -0
- lorebase_store/_migrations/versions/0028_operation_deferred_events.py +71 -0
- lorebase_store/_migrations/versions/0029_agent_trace_sessions.py +108 -0
- lorebase_store/_migrations/versions/0030_path_fanout.py +31 -0
- lorebase_store/_migrations/versions/0031_branch_builds.py +91 -0
- lorebase_store/_migrations/versions/0032_lineage_revisions.py +35 -0
- lorebase_store/_migrations/versions/0033_vault_moved_tokens.py +30 -0
- lorebase_store/_migrations/versions/0034_inference_endpoint_modes.py +73 -0
- lorebase_store/_migrations/versions/0035_search_truncation.py +104 -0
- lorebase_store/_migrations/versions/0036_lineage_maps.py +325 -0
- lorebase_store/_migrations/versions/0037_bm25_search.py +346 -0
- lorebase_store/auth/__init__.py +52 -0
- lorebase_store/auth/api_keys.py +161 -0
- lorebase_store/auth/audit.py +382 -0
- lorebase_store/auth/checkpoints.py +185 -0
- lorebase_store/auth/grants.py +161 -0
- lorebase_store/auth/principals.py +158 -0
- lorebase_store/auth/scope.py +70 -0
- lorebase_store/auth/sessions.py +153 -0
- lorebase_store/auth/unit.py +53 -0
- lorebase_store/auth/usage.py +70 -0
- lorebase_store/blobs.py +73 -0
- lorebase_store/bm25.py +346 -0
- lorebase_store/bulk.py +147 -0
- lorebase_store/bundle.py +1830 -0
- lorebase_store/changefeed.py +261 -0
- lorebase_store/commit/__init__.py +42 -0
- lorebase_store/commit/changes.py +67 -0
- lorebase_store/commit/errors.py +60 -0
- lorebase_store/commit/migrations.py +335 -0
- lorebase_store/commit/pipeline.py +754 -0
- lorebase_store/commit/schema.py +123 -0
- lorebase_store/db.py +58 -0
- lorebase_store/definer.py +50 -0
- lorebase_store/digests.py +99 -0
- lorebase_store/embeddings.py +444 -0
- lorebase_store/endpoint_modes.py +59 -0
- lorebase_store/extraction/__init__.py +61 -0
- lorebase_store/extraction/items.py +187 -0
- lorebase_store/extraction/materialize.py +364 -0
- lorebase_store/extraction/proposal.py +65 -0
- lorebase_store/extraction/review.py +168 -0
- lorebase_store/gc.py +970 -0
- lorebase_store/indexes.py +1033 -0
- lorebase_store/jobs.py +651 -0
- lorebase_store/keyring.py +72 -0
- lorebase_store/layout.py +335 -0
- lorebase_store/materialize/__init__.py +103 -0
- lorebase_store/materialize/apply.py +436 -0
- lorebase_store/materialize/background.py +1184 -0
- lorebase_store/materialize/branch.py +268 -0
- lorebase_store/materialize/build.py +536 -0
- lorebase_store/materialize/derived.py +540 -0
- lorebase_store/materialize/lineage_backfill.py +502 -0
- lorebase_store/materialize/links.py +266 -0
- lorebase_store/materialize/overlay.py +292 -0
- lorebase_store/materialize/paths.py +315 -0
- lorebase_store/materialize/rebuild.py +326 -0
- lorebase_store/materialize/rows.py +153 -0
- lorebase_store/materialize/sensitivity.py +66 -0
- lorebase_store/materialize/snapshot.py +205 -0
- lorebase_store/materialize/stale.py +444 -0
- lorebase_store/materialize/verify.py +321 -0
- lorebase_store/merging/__init__.py +39 -0
- lorebase_store/merging/attempts.py +334 -0
- lorebase_store/merging/lineage.py +123 -0
- lorebase_store/merging/service.py +652 -0
- lorebase_store/migrations.py +133 -0
- lorebase_store/models/__init__.py +136 -0
- lorebase_store/models/base.py +64 -0
- lorebase_store/models/enums.py +132 -0
- lorebase_store/models/governance.py +268 -0
- lorebase_store/models/ingestion.py +288 -0
- lorebase_store/models/materialized.py +277 -0
- lorebase_store/models/proposals.py +195 -0
- lorebase_store/models/queues.py +87 -0
- lorebase_store/models/tracing.py +116 -0
- lorebase_store/models/versioning.py +222 -0
- lorebase_store/models/webhooks.py +96 -0
- lorebase_store/nodestore.py +384 -0
- lorebase_store/objectstore.py +162 -0
- lorebase_store/outbox_events.py +166 -0
- lorebase_store/profiling/__init__.py +58 -0
- lorebase_store/profiling/delimited.py +109 -0
- lorebase_store/profiling/postgres.py +211 -0
- lorebase_store/profiling/record_files.py +127 -0
- lorebase_store/profiling/records.py +92 -0
- lorebase_store/profiling/sql_databases.py +298 -0
- lorebase_store/ratelimit.py +129 -0
- lorebase_store/reads.py +1491 -0
- lorebase_store/replicas.py +434 -0
- lorebase_store/repositories/__init__.py +152 -0
- lorebase_store/repositories/changesets.py +59 -0
- lorebase_store/repositories/deferred_events.py +142 -0
- lorebase_store/repositories/documents.py +305 -0
- lorebase_store/repositories/domains.py +97 -0
- lorebase_store/repositories/events.py +205 -0
- lorebase_store/repositories/index_view.py +489 -0
- lorebase_store/repositories/invocations.py +68 -0
- lorebase_store/repositories/materializations.py +276 -0
- lorebase_store/repositories/materialized.py +1129 -0
- lorebase_store/repositories/merges.py +417 -0
- lorebase_store/repositories/proposal_items.py +199 -0
- lorebase_store/repositories/proposals.py +184 -0
- lorebase_store/repositories/provenance.py +77 -0
- lorebase_store/repositories/refs.py +452 -0
- lorebase_store/repositories/revisions.py +273 -0
- lorebase_store/repositories/scope.py +33 -0
- lorebase_store/repositories/source_runs.py +123 -0
- lorebase_store/repositories/suggestions.py +638 -0
- lorebase_store/runtime.py +87 -0
- lorebase_store/schema_cache.py +50 -0
- lorebase_store/settings.py +879 -0
- lorebase_store/storage.py +1478 -0
- lorebase_store/telemetry.py +142 -0
- lorebase_store/testing.py +108 -0
- lorebase_store/tracing.py +505 -0
- lorebase_store/traverse.py +578 -0
- lorebase_store/vault/__init__.py +50 -0
- lorebase_store/vault/keys.py +216 -0
- lorebase_store/vault/quotes.py +133 -0
- lorebase_store/vault/rotation.py +209 -0
- lorebase_store/vault/settings.py +152 -0
- lorebase_store/vault/store.py +987 -0
- lorebase_store/vault/transfer.py +558 -0
- lorebase_store/webhooks/__init__.py +24 -0
- lorebase_store/webhooks/delivery.py +637 -0
- lorebase_store/webhooks/keys.py +126 -0
- lorebase_store/webhooks/repository.py +142 -0
- lorebase_store/webhooks/settings.py +138 -0
- lorebase_store/webhooks/signing.py +50 -0
- lorebase_store-0.2.3.dist-info/METADATA +13 -0
- lorebase_store-0.2.3.dist-info/RECORD +163 -0
- lorebase_store-0.2.3.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Run Alembic migrations programmatically and expose the expected head revisions.
|
|
2
|
+
|
|
3
|
+
The Alembic environment lives in `packages/store/migrations` (shipped in the wheel as
|
|
4
|
+
`lorebase_store/_migrations`). Settings not passed explicitly are loaded with `load_settings()`
|
|
5
|
+
by the environment; revisions read `config.attributes["store_settings"]`.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from collections.abc import Iterable
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from alembic import command
|
|
16
|
+
from alembic.config import Config
|
|
17
|
+
from alembic.script import ScriptDirectory
|
|
18
|
+
from alembic.util import CommandError
|
|
19
|
+
|
|
20
|
+
from lorebase_store.settings import DatabaseSettings, StoreSettings
|
|
21
|
+
|
|
22
|
+
DATABASE_ATTRIBUTE = "database_settings"
|
|
23
|
+
STORE_ATTRIBUTE = "store_settings"
|
|
24
|
+
URL_ATTRIBUTE = "database_url"
|
|
25
|
+
|
|
26
|
+
DYNAMIC_INDEX_PREFIXES = ("embeddings_hnsw_", "mat_records_attr_", "ix_mat_records_bm25")
|
|
27
|
+
"""Indexes created from configuration or schema at runtime, the optional BM25 index
|
|
28
|
+
(`lorebase_store.bm25`) included; schema comparison skips them."""
|
|
29
|
+
|
|
30
|
+
PROFILE_INDEXES = ("ix_mat_records_values", "ix_mat_lexicon_branch_word")
|
|
31
|
+
"""Indexes of the models that a storage profile may leave out (`lorebase_store.storage`);
|
|
32
|
+
schema comparison skips them whether they exist or not."""
|
|
33
|
+
|
|
34
|
+
PARTITION_NAME = re.compile(r"^(?P<parent>[a-z_]+)_p(?P<remainder>\d+)$")
|
|
35
|
+
"""Hash partitions are named `<table>_p<remainder>`."""
|
|
36
|
+
|
|
37
|
+
_PACKAGED_SCRIPTS = Path(__file__).resolve().parent / "_migrations"
|
|
38
|
+
_SOURCE_SCRIPTS = Path(__file__).resolve().parents[2] / "migrations"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def script_location() -> Path:
|
|
42
|
+
"""Directory of the Alembic environment: the packaged copy, else the source tree."""
|
|
43
|
+
return _PACKAGED_SCRIPTS if _PACKAGED_SCRIPTS.is_dir() else _SOURCE_SCRIPTS
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def include_object(
|
|
47
|
+
obj: Any, name: str | None, type_: str, reflected: bool, compare_to: Any
|
|
48
|
+
) -> bool:
|
|
49
|
+
"""Schema comparison filter: skip hash partitions, runtime-managed indexes and the
|
|
50
|
+
indexes a storage profile manages."""
|
|
51
|
+
if type_ == "index" and name in PROFILE_INDEXES:
|
|
52
|
+
return False
|
|
53
|
+
if not reflected or compare_to is not None or name is None:
|
|
54
|
+
return True
|
|
55
|
+
if type_ == "table":
|
|
56
|
+
return PARTITION_NAME.match(name) is None
|
|
57
|
+
if type_ == "index":
|
|
58
|
+
return not name.startswith(DYNAMIC_INDEX_PREFIXES)
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def alembic_config(
|
|
63
|
+
database: DatabaseSettings | None = None,
|
|
64
|
+
store: StoreSettings | None = None,
|
|
65
|
+
*,
|
|
66
|
+
url: str | None = None,
|
|
67
|
+
) -> Config:
|
|
68
|
+
"""Alembic configuration; `url` overrides `database.dsn`."""
|
|
69
|
+
config = Config()
|
|
70
|
+
config.set_main_option("script_location", str(script_location()))
|
|
71
|
+
for key, value in (
|
|
72
|
+
(DATABASE_ATTRIBUTE, database),
|
|
73
|
+
(STORE_ATTRIBUTE, store),
|
|
74
|
+
(URL_ATTRIBUTE, url),
|
|
75
|
+
):
|
|
76
|
+
if value is not None:
|
|
77
|
+
config.attributes[key] = value
|
|
78
|
+
return config
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def head_revisions() -> tuple[str, ...]:
|
|
82
|
+
"""Alembic head revisions of this code, for readiness checks."""
|
|
83
|
+
return tuple(ScriptDirectory.from_config(alembic_config()).get_heads())
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class RevisionMismatchError(CommandError):
|
|
87
|
+
"""The database is at a revision this code does not know: a newer version migrated it."""
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def unknown_revisions(script: ScriptDirectory, current: Iterable[str]) -> tuple[str, ...]:
|
|
91
|
+
"""Revisions of `current` (the database's) that the migration scripts of this code lack."""
|
|
92
|
+
known = {revision.revision for revision in script.walk_revisions()}
|
|
93
|
+
return tuple(sorted({revision for revision in current if revision not in known}))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def check_known_revisions(script: ScriptDirectory, current: Iterable[str]) -> None:
|
|
97
|
+
"""Refuse to migrate a database that a newer version already migrated.
|
|
98
|
+
|
|
99
|
+
Alembic alone stops with "Can't locate revision"; this names both sides and the way out.
|
|
100
|
+
"""
|
|
101
|
+
unknown = unknown_revisions(script, current)
|
|
102
|
+
if not unknown:
|
|
103
|
+
return
|
|
104
|
+
heads = ", ".join(sorted(script.get_heads())) or "none"
|
|
105
|
+
raise RevisionMismatchError(
|
|
106
|
+
f"the database is at revision {', '.join(unknown)}, which this code does not know "
|
|
107
|
+
f"(its newest revision is {heads}): a newer Lorebase migrated this database. Run the "
|
|
108
|
+
"version that did (with docker compose: `docker compose build` then `up`, or "
|
|
109
|
+
"`make up`, which rebuild the images from the checkout), or restore a backup taken "
|
|
110
|
+
"before that upgrade. Older code cannot downgrade it."
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def upgrade(
|
|
115
|
+
revision: str = "head",
|
|
116
|
+
*,
|
|
117
|
+
database: DatabaseSettings | None = None,
|
|
118
|
+
store: StoreSettings | None = None,
|
|
119
|
+
url: str | None = None,
|
|
120
|
+
) -> None:
|
|
121
|
+
"""Upgrade the database to `revision`."""
|
|
122
|
+
command.upgrade(alembic_config(database, store, url=url), revision)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def downgrade(
|
|
126
|
+
revision: str = "base",
|
|
127
|
+
*,
|
|
128
|
+
database: DatabaseSettings | None = None,
|
|
129
|
+
store: StoreSettings | None = None,
|
|
130
|
+
url: str | None = None,
|
|
131
|
+
) -> None:
|
|
132
|
+
"""Downgrade the database to `revision`."""
|
|
133
|
+
command.downgrade(alembic_config(database, store, url=url), revision)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""SQLAlchemy models of every Lorebase table (design 7). `metadata` is the migration target."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from lorebase_store.models.base import Base
|
|
6
|
+
from lorebase_store.models.governance import (
|
|
7
|
+
ApiKey,
|
|
8
|
+
ApiKeyUsage,
|
|
9
|
+
AuditEntry,
|
|
10
|
+
AuditReadEntry,
|
|
11
|
+
Grant,
|
|
12
|
+
Group,
|
|
13
|
+
GroupMember,
|
|
14
|
+
OperationDeferredEvent,
|
|
15
|
+
OperationInvocation,
|
|
16
|
+
Principal,
|
|
17
|
+
RateLimitBucket,
|
|
18
|
+
WebSession,
|
|
19
|
+
)
|
|
20
|
+
from lorebase_store.models.ingestion import (
|
|
21
|
+
Document,
|
|
22
|
+
DocumentBlob,
|
|
23
|
+
DocumentChunk,
|
|
24
|
+
ExtractionCacheEntry,
|
|
25
|
+
ExtractionJob,
|
|
26
|
+
InferenceEndpointMode,
|
|
27
|
+
InstallationSecret,
|
|
28
|
+
SchemaSuggestion,
|
|
29
|
+
SourceRun,
|
|
30
|
+
VaultEntry,
|
|
31
|
+
VaultLineage,
|
|
32
|
+
VaultTombstone,
|
|
33
|
+
)
|
|
34
|
+
from lorebase_store.models.materialized import (
|
|
35
|
+
BranchMaterialization,
|
|
36
|
+
Embedding,
|
|
37
|
+
EmbeddingCursor,
|
|
38
|
+
MatHistory,
|
|
39
|
+
MatLexicon,
|
|
40
|
+
MatLineageMap,
|
|
41
|
+
MatLink,
|
|
42
|
+
MatRecord,
|
|
43
|
+
MatSchema,
|
|
44
|
+
StorageTask,
|
|
45
|
+
)
|
|
46
|
+
from lorebase_store.models.proposals import (
|
|
47
|
+
Conflict,
|
|
48
|
+
ConflictResolution,
|
|
49
|
+
MergeAttempt,
|
|
50
|
+
Proposal,
|
|
51
|
+
ProposalItem,
|
|
52
|
+
ProposalReview,
|
|
53
|
+
)
|
|
54
|
+
from lorebase_store.models.queues import Job, OutboxConsumer, OutboxEvent, OutboxPending
|
|
55
|
+
from lorebase_store.models.tracing import (
|
|
56
|
+
AgentTraceSession,
|
|
57
|
+
AgentTraceSessionDomain,
|
|
58
|
+
AgentTraceStep,
|
|
59
|
+
)
|
|
60
|
+
from lorebase_store.models.versioning import (
|
|
61
|
+
ChangesetEntry,
|
|
62
|
+
Domain,
|
|
63
|
+
Provenance,
|
|
64
|
+
Ref,
|
|
65
|
+
RefLogEntry,
|
|
66
|
+
Revision,
|
|
67
|
+
RevisionParent,
|
|
68
|
+
StoredObject,
|
|
69
|
+
TreeNode,
|
|
70
|
+
)
|
|
71
|
+
from lorebase_store.models.webhooks import Webhook, WebhookDelivery
|
|
72
|
+
|
|
73
|
+
metadata = Base.metadata
|
|
74
|
+
|
|
75
|
+
__all__ = [
|
|
76
|
+
"AgentTraceSession",
|
|
77
|
+
"AgentTraceSessionDomain",
|
|
78
|
+
"AgentTraceStep",
|
|
79
|
+
"ApiKey",
|
|
80
|
+
"ApiKeyUsage",
|
|
81
|
+
"AuditEntry",
|
|
82
|
+
"AuditReadEntry",
|
|
83
|
+
"Base",
|
|
84
|
+
"BranchMaterialization",
|
|
85
|
+
"ChangesetEntry",
|
|
86
|
+
"Conflict",
|
|
87
|
+
"ConflictResolution",
|
|
88
|
+
"Document",
|
|
89
|
+
"DocumentBlob",
|
|
90
|
+
"DocumentChunk",
|
|
91
|
+
"Domain",
|
|
92
|
+
"Embedding",
|
|
93
|
+
"EmbeddingCursor",
|
|
94
|
+
"ExtractionCacheEntry",
|
|
95
|
+
"ExtractionJob",
|
|
96
|
+
"Grant",
|
|
97
|
+
"Group",
|
|
98
|
+
"GroupMember",
|
|
99
|
+
"InferenceEndpointMode",
|
|
100
|
+
"InstallationSecret",
|
|
101
|
+
"Job",
|
|
102
|
+
"MatHistory",
|
|
103
|
+
"MatLexicon",
|
|
104
|
+
"MatLineageMap",
|
|
105
|
+
"MatLink",
|
|
106
|
+
"MatRecord",
|
|
107
|
+
"MatSchema",
|
|
108
|
+
"MergeAttempt",
|
|
109
|
+
"OperationDeferredEvent",
|
|
110
|
+
"OperationInvocation",
|
|
111
|
+
"OutboxConsumer",
|
|
112
|
+
"OutboxEvent",
|
|
113
|
+
"OutboxPending",
|
|
114
|
+
"Principal",
|
|
115
|
+
"Proposal",
|
|
116
|
+
"ProposalItem",
|
|
117
|
+
"ProposalReview",
|
|
118
|
+
"Provenance",
|
|
119
|
+
"RateLimitBucket",
|
|
120
|
+
"Ref",
|
|
121
|
+
"RefLogEntry",
|
|
122
|
+
"Revision",
|
|
123
|
+
"RevisionParent",
|
|
124
|
+
"SchemaSuggestion",
|
|
125
|
+
"SourceRun",
|
|
126
|
+
"StorageTask",
|
|
127
|
+
"StoredObject",
|
|
128
|
+
"TreeNode",
|
|
129
|
+
"VaultEntry",
|
|
130
|
+
"VaultLineage",
|
|
131
|
+
"VaultTombstone",
|
|
132
|
+
"WebSession",
|
|
133
|
+
"Webhook",
|
|
134
|
+
"WebhookDelivery",
|
|
135
|
+
"metadata",
|
|
136
|
+
]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Declarative base, constraint naming convention and shared column helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from enum import StrEnum
|
|
7
|
+
from typing import Annotated, Any
|
|
8
|
+
|
|
9
|
+
from sqlalchemy import (
|
|
10
|
+
CheckConstraint,
|
|
11
|
+
DateTime,
|
|
12
|
+
Enum,
|
|
13
|
+
ForeignKeyConstraint,
|
|
14
|
+
LargeBinary,
|
|
15
|
+
MetaData,
|
|
16
|
+
Text,
|
|
17
|
+
)
|
|
18
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
19
|
+
from sqlalchemy.orm import DeclarativeBase, mapped_column
|
|
20
|
+
|
|
21
|
+
NAMING_CONVENTION = {
|
|
22
|
+
"ix": "ix_%(table_name)s_%(column_0_N_name)s",
|
|
23
|
+
"uq": "uq_%(table_name)s_%(column_0_N_name)s",
|
|
24
|
+
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
|
25
|
+
"fk": "fk_%(table_name)s_%(column_0_N_name)s_%(referred_table_name)s",
|
|
26
|
+
"pk": "pk_%(table_name)s",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
HASH_PARTITIONED = {"postgresql_partition_by": "HASH (domain_id)"}
|
|
30
|
+
"""Table option for tables hash-partitioned on `domain_id` (partitions come from migrations)."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Base(DeclarativeBase):
|
|
34
|
+
"""Base of every Lorebase table."""
|
|
35
|
+
|
|
36
|
+
metadata = MetaData(naming_convention=NAMING_CONVENTION)
|
|
37
|
+
type_annotation_map = { # noqa: RUF012
|
|
38
|
+
dict[str, Any]: JSONB,
|
|
39
|
+
bytes: LargeBinary,
|
|
40
|
+
str: Text,
|
|
41
|
+
datetime: DateTime(timezone=True),
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
H32 = bytes
|
|
46
|
+
"""A 32-byte SHA-256 digest stored as `bytea`."""
|
|
47
|
+
|
|
48
|
+
DomainKey = Annotated[str, mapped_column(Text, primary_key=True)]
|
|
49
|
+
"""`domain_id` as the leading primary key column."""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def h32_check(column: str) -> CheckConstraint:
|
|
53
|
+
"""Check that `column` holds exactly 32 bytes."""
|
|
54
|
+
return CheckConstraint(f"octet_length({column}) = 32", name=f"{column}_h32")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def domain_fk(*, ondelete: str = "CASCADE") -> ForeignKeyConstraint:
|
|
58
|
+
"""`domain_id` references `domains.id`; rows go with their Domain."""
|
|
59
|
+
return ForeignKeyConstraint(["domain_id"], ["domains.id"], ondelete=ondelete)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def pg_enum(enum: type[StrEnum], name: str) -> Enum:
|
|
63
|
+
"""Native Postgres enum type `name` storing the member values of `enum`."""
|
|
64
|
+
return Enum(enum, name=name, values_callable=lambda members: [m.value for m in members])
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Closed value sets stored as native Postgres enum types."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
|
|
7
|
+
from lorebase_store.models.base import pg_enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RefKind(StrEnum):
|
|
11
|
+
"""`branch` moves; `tag` is an immutable pointer (design 6.5); `snapshot` holds the
|
|
12
|
+
materialized rows of a past Revision for reads at it (`materialize.snapshot`)."""
|
|
13
|
+
|
|
14
|
+
BRANCH = "branch"
|
|
15
|
+
TAG = "tag"
|
|
16
|
+
SNAPSHOT = "snapshot"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Materialization(StrEnum):
|
|
20
|
+
"""Branch materialization mode (design 6.11)."""
|
|
21
|
+
|
|
22
|
+
FULL = "full"
|
|
23
|
+
OVERLAY = "overlay"
|
|
24
|
+
NONE = "none"
|
|
25
|
+
BUILDING = "building"
|
|
26
|
+
"""A full branch whose rows a background job is still writing from its tree; reads of
|
|
27
|
+
its head and commits wait for it (`materialize.background`)."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ProposalOrigin(StrEnum):
|
|
31
|
+
"""What opened a Proposal."""
|
|
32
|
+
|
|
33
|
+
MANUAL = "manual"
|
|
34
|
+
SOURCE_SYNC = "source_sync"
|
|
35
|
+
EXTRACTION = "extraction"
|
|
36
|
+
OPERATION = "operation"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ProposalStatus(StrEnum):
|
|
40
|
+
"""Proposal lifecycle."""
|
|
41
|
+
|
|
42
|
+
OPEN = "open"
|
|
43
|
+
MERGED = "merged"
|
|
44
|
+
CLOSED = "closed"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ReviewVerdict(StrEnum):
|
|
48
|
+
"""Outcome of one Proposal review."""
|
|
49
|
+
|
|
50
|
+
APPROVE = "approve"
|
|
51
|
+
REQUEST_CHANGES = "request_changes"
|
|
52
|
+
COMMENT = "comment"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ItemDecision(StrEnum):
|
|
56
|
+
"""Decision on one extraction Proposal item."""
|
|
57
|
+
|
|
58
|
+
PENDING = "pending"
|
|
59
|
+
ACCEPTED = "accepted"
|
|
60
|
+
REJECTED = "rejected"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class MergeAttemptStatus(StrEnum):
|
|
64
|
+
"""Merge attempt lifecycle (design 6.8 step 5, 6.10)."""
|
|
65
|
+
|
|
66
|
+
CONFLICTED = "conflicted"
|
|
67
|
+
STALE = "stale"
|
|
68
|
+
RESOLVED = "resolved"
|
|
69
|
+
MERGED = "merged"
|
|
70
|
+
ABANDONED = "abandoned"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class PrincipalType(StrEnum):
|
|
74
|
+
"""Kind of authenticated actor (design 13.2)."""
|
|
75
|
+
|
|
76
|
+
USER = "user"
|
|
77
|
+
SERVICE = "service"
|
|
78
|
+
API_KEY = "api_key"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class GrantScope(StrEnum):
|
|
82
|
+
"""What a grant applies to (design 10.2)."""
|
|
83
|
+
|
|
84
|
+
DOMAIN = "domain"
|
|
85
|
+
KIND = "kind"
|
|
86
|
+
OPERATION = "operation"
|
|
87
|
+
BRANCH = "branch"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class InvocationStatus(StrEnum):
|
|
91
|
+
"""Operation invocation status (design 10.1)."""
|
|
92
|
+
|
|
93
|
+
PENDING = "pending"
|
|
94
|
+
COMMITTED = "committed"
|
|
95
|
+
PROPOSED = "proposed"
|
|
96
|
+
REJECTED = "rejected"
|
|
97
|
+
DRY_RUN = "dry_run"
|
|
98
|
+
FAILED = "failed"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class JobStatus(StrEnum):
|
|
102
|
+
"""Background job lifecycle; `queued` jobs are claimed with SKIP LOCKED."""
|
|
103
|
+
|
|
104
|
+
QUEUED = "queued"
|
|
105
|
+
RUNNING = "running"
|
|
106
|
+
SUCCEEDED = "succeeded"
|
|
107
|
+
FAILED = "failed"
|
|
108
|
+
CANCELLED = "cancelled"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class RunStatus(StrEnum):
|
|
112
|
+
"""Lifecycle of Source runs and extraction jobs."""
|
|
113
|
+
|
|
114
|
+
QUEUED = "queued"
|
|
115
|
+
RUNNING = "running"
|
|
116
|
+
SUCCEEDED = "succeeded"
|
|
117
|
+
FAILED = "failed"
|
|
118
|
+
CANCELLED = "cancelled"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
REF_KIND = pg_enum(RefKind, "ref_kind")
|
|
122
|
+
MATERIALIZATION = pg_enum(Materialization, "materialization")
|
|
123
|
+
PROPOSAL_ORIGIN = pg_enum(ProposalOrigin, "proposal_origin")
|
|
124
|
+
PROPOSAL_STATUS = pg_enum(ProposalStatus, "proposal_status")
|
|
125
|
+
REVIEW_VERDICT = pg_enum(ReviewVerdict, "review_verdict")
|
|
126
|
+
ITEM_DECISION = pg_enum(ItemDecision, "item_decision")
|
|
127
|
+
MERGE_ATTEMPT_STATUS = pg_enum(MergeAttemptStatus, "merge_attempt_status")
|
|
128
|
+
PRINCIPAL_TYPE = pg_enum(PrincipalType, "principal_type")
|
|
129
|
+
GRANT_SCOPE = pg_enum(GrantScope, "grant_scope")
|
|
130
|
+
INVOCATION_STATUS = pg_enum(InvocationStatus, "invocation_status")
|
|
131
|
+
JOB_STATUS = pg_enum(JobStatus, "job_status")
|
|
132
|
+
RUN_STATUS = pg_enum(RunStatus, "run_status")
|