Skip to content

Commit db29758

Browse files
authored
Merge pull request #605 from MerginMaps/fix_construct_checkpoint
Fix issue with gpkg reconstruction from merged diffs
2 parents d5d5753 + 51c8353 commit db29758

2 files changed

Lines changed: 45 additions & 7 deletions

File tree

server/mergin/sync/models.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,8 +1017,9 @@ def construct_checkpoint(self) -> bool:
10171017
)
10181018

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

10241025
# find diff in table and on disk

server/mergin/tests/test_file_restore.py

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import pytest
66
import shutil
7+
from sqlalchemy import tuple_
78
from sqlalchemy.orm.attributes import flag_modified
89

910
from ..app import db
@@ -15,6 +16,7 @@
1516
Project,
1617
GeodiffActionHistory,
1718
)
19+
from ..sync.utils import Checkpoint
1820
from . import test_project_dir, TMP_DIR
1921
from .utils import (
2022
create_project,
@@ -250,11 +252,46 @@ def test_version_file_restore(diff_project):
250252
test_file = os.path.join(diff_project.storage.project_dir, "v30", "test.gpkg")
251253
os.rename(test_file, test_file + "_backup")
252254
diff_project.storage.restore_versioned_file("test.gpkg", 30)
255+
checkpoints = Checkpoint.get_checkpoints(9, 30)
253256
assert os.path.exists(test_file)
254257
assert gpkgs_are_equal(test_file, test_file + "_backup")
255-
assert (
256-
FileDiff.query.filter_by(file_path_id=file_path_id)
257-
.filter(FileDiff.rank > 0)
258-
.count()
259-
> 0
258+
assert FileDiff.query.filter_by(file_path_id=file_path_id).filter(
259+
tuple_(FileDiff.rank, FileDiff.version).in_(
260+
[(item.rank, item.end) for item in checkpoints]
261+
)
262+
).count() == len(checkpoints)
263+
264+
# let's create new project with basefile at v1 (which can be start of multiple checkpoints)
265+
working_dir = os.path.join(TMP_DIR, "restore_from_diffs")
266+
basefile = os.path.join(working_dir, "base.gpkg")
267+
project = _prepare_restore_project(working_dir)
268+
file_path_id = (
269+
ProjectFilePath.query.filter_by(project_id=project.id, path="base.gpkg")
270+
.first()
271+
.id
260272
)
273+
274+
for i in range(17):
275+
sql = "INSERT INTO simple (geometry, name) VALUES (GeomFromText('POINT(24.5, 38.2)', 4326), 'insert_test')"
276+
execute_query(basefile, sql)
277+
pv_latest = push_change(project, "updated", "base.gpkg", working_dir)
278+
assert project.latest_version == pv_latest.name
279+
assert os.path.exists(
280+
os.path.join(
281+
project.storage.project_dir,
282+
ProjectVersion.to_v_name(pv_latest.name),
283+
"base.gpkg",
284+
)
285+
)
286+
287+
test_file = os.path.join(project.storage.project_dir, "v17", "base.gpkg")
288+
os.rename(test_file, test_file + "_backup")
289+
project.storage.restore_versioned_file("base.gpkg", 17)
290+
checkpoints = Checkpoint.get_checkpoints(1, 17)
291+
assert os.path.exists(test_file)
292+
assert gpkgs_are_equal(test_file, test_file + "_backup")
293+
assert FileDiff.query.filter_by(file_path_id=file_path_id).filter(
294+
tuple_(FileDiff.rank, FileDiff.version).in_(
295+
[(item.rank, item.end) for item in checkpoints]
296+
)
297+
).count() == len(checkpoints)

0 commit comments

Comments
 (0)