Add migrate:msgspec for changes in schema that don't require version bump. Rename the other migrations to migrate:sql and migrate:v{N}.
This commit is contained in:
+26
-5
@@ -105,7 +105,7 @@ def create_change_record(
|
||||
|
||||
|
||||
# Actions that are allowed to create a new database file
|
||||
_BOOTSTRAP_ACTIONS = frozenset({"bootstrap", "migrate"})
|
||||
_BOOTSTRAP_ACTIONS = frozenset({"bootstrap", "migrate:sql"})
|
||||
|
||||
|
||||
async def flush_changes(
|
||||
@@ -187,15 +187,35 @@ class JsonlStore:
|
||||
# Update previous state to migrated data FIRST (to avoid transaction hardening reset)
|
||||
self._previous_builtins = data_dict
|
||||
|
||||
# Persist migration by manually computing and queueing the diff
|
||||
# Persist version migration by manually computing and queueing the diff
|
||||
if migrated:
|
||||
new_version = data_dict.get("v", 1)
|
||||
diff = compute_diff(original_dict, data_dict)
|
||||
if diff:
|
||||
action = f"migrate:v{new_version}"
|
||||
self._pending_changes.append(
|
||||
create_change_record("migrate", diff, user=None)
|
||||
create_change_record(action, diff, user=None)
|
||||
)
|
||||
_logger.info("Queued migration changes for persistence")
|
||||
diff_json = json.dumps(diff, default=str)
|
||||
print(f"{action}: {diff_json}", file=sys.stderr)
|
||||
await self.flush()
|
||||
# Update original_dict to reflect persisted state
|
||||
original_dict = copy.deepcopy(data_dict)
|
||||
|
||||
# Normalize via msgspec round-trip (handles omit_defaults etc.)
|
||||
# This ensures _previous_builtins matches what msgspec would produce
|
||||
normalized_dict = msgspec.to_builtins(self.db)
|
||||
diff = compute_diff(original_dict, normalized_dict)
|
||||
if diff:
|
||||
action = "migrate:msgspec"
|
||||
self._pending_changes.append(
|
||||
create_change_record(action, diff, user=None)
|
||||
)
|
||||
diff_json = json.dumps(diff, default=str)
|
||||
print(f"{action}: {diff_json}", file=sys.stderr)
|
||||
await self.flush()
|
||||
# Update _previous_builtins to normalized state
|
||||
self._previous_builtins = normalized_dict
|
||||
else:
|
||||
# No data loaded - _previous_builtins stays as empty dict
|
||||
pass
|
||||
@@ -252,7 +272,8 @@ class JsonlStore:
|
||||
current_state = msgspec.to_builtins(self.db)
|
||||
if current_state != self._previous_builtins:
|
||||
# Allow bootstrap/migrate to create a new database from empty state
|
||||
if action in _BOOTSTRAP_ACTIONS and not self._previous_builtins:
|
||||
is_bootstrap = action in _BOOTSTRAP_ACTIONS or action.startswith("migrate:")
|
||||
if is_bootstrap and not self._previous_builtins:
|
||||
pass # Expected: creating database from scratch
|
||||
else:
|
||||
diff = compute_diff(self._previous_builtins, current_state)
|
||||
|
||||
@@ -5,10 +5,6 @@ Migrations are applied during database load based on the version field.
|
||||
Each migration should be idempotent and only run when needed.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def apply_migrations(data_dict: dict) -> bool:
|
||||
"""Apply any pending schema migrations to the database dictionary.
|
||||
@@ -29,6 +25,5 @@ def apply_migrations(data_dict: dict) -> bool:
|
||||
org_data.pop("created_at", None)
|
||||
data_dict["v"] = 1
|
||||
migrated = True
|
||||
_logger.info("Applied schema migration: v0 -> v1 (removed org.created_at)")
|
||||
|
||||
return migrated
|
||||
|
||||
@@ -248,7 +248,7 @@ async def migrate_from_sql(
|
||||
print(f" Migrated {len(token_models)} reset tokens")
|
||||
|
||||
# Queue and flush all changes using the transaction mechanism
|
||||
with db.transaction("migrate"):
|
||||
with db.transaction("migrate:sql"):
|
||||
pass # All data already added to _data, transaction commits on exit
|
||||
|
||||
await store.flush()
|
||||
|
||||
Reference in New Issue
Block a user