Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions server/mergin/sync/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1017,8 +1017,9 @@ def construct_checkpoint(self) -> bool:
)

for item in cached_items:
# basefile is a start of the diff chain
if item.start <= basefile.project_version_name:
# basefile is a start of the diff chain, item cannot cross over it,
# but merged diffs can start with basefile version containing changes since then
if item.start < basefile.project_version_name:
continue

# find diff in table and on disk
Expand Down
47 changes: 42 additions & 5 deletions server/mergin/tests/test_file_restore.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import pytest
import shutil
from sqlalchemy import tuple_
from sqlalchemy.orm.attributes import flag_modified

from ..app import db
Expand All @@ -15,6 +16,7 @@
Project,
GeodiffActionHistory,
)
from ..sync.utils import Checkpoint
from . import test_project_dir, TMP_DIR
from .utils import (
create_project,
Expand Down Expand Up @@ -250,11 +252,46 @@ def test_version_file_restore(diff_project):
test_file = os.path.join(diff_project.storage.project_dir, "v30", "test.gpkg")
os.rename(test_file, test_file + "_backup")
diff_project.storage.restore_versioned_file("test.gpkg", 30)
checkpoints = Checkpoint.get_checkpoints(9, 30)
assert os.path.exists(test_file)
assert gpkgs_are_equal(test_file, test_file + "_backup")
assert (
FileDiff.query.filter_by(file_path_id=file_path_id)
.filter(FileDiff.rank > 0)
.count()
> 0
assert FileDiff.query.filter_by(file_path_id=file_path_id).filter(
tuple_(FileDiff.rank, FileDiff.version).in_(
[(item.rank, item.end) for item in checkpoints]
)
).count() == len(checkpoints)

# let's create new project with basefile at v1 (which can be start of multiple checkpoints)
working_dir = os.path.join(TMP_DIR, "restore_from_diffs")
basefile = os.path.join(working_dir, "base.gpkg")
project = _prepare_restore_project(working_dir)
file_path_id = (
ProjectFilePath.query.filter_by(project_id=project.id, path="base.gpkg")
.first()
.id
)

for i in range(17):
sql = "INSERT INTO simple (geometry, name) VALUES (GeomFromText('POINT(24.5, 38.2)', 4326), 'insert_test')"
execute_query(basefile, sql)
pv_latest = push_change(project, "updated", "base.gpkg", working_dir)
assert project.latest_version == pv_latest.name
assert os.path.exists(
os.path.join(
project.storage.project_dir,
ProjectVersion.to_v_name(pv_latest.name),
"base.gpkg",
)
)

test_file = os.path.join(project.storage.project_dir, "v17", "base.gpkg")
os.rename(test_file, test_file + "_backup")
project.storage.restore_versioned_file("base.gpkg", 17)
checkpoints = Checkpoint.get_checkpoints(1, 17)
assert os.path.exists(test_file)
assert gpkgs_are_equal(test_file, test_file + "_backup")
assert FileDiff.query.filter_by(file_path_id=file_path_id).filter(
tuple_(FileDiff.rank, FileDiff.version).in_(
[(item.rank, item.end) for item in checkpoints]
)
).count() == len(checkpoints)
Loading