Skip to content

Commit 5eee86b

Browse files
committed
feat: only offline the subset that matches all layer's filters
If a project has layer1 and layer2 that have the same data source, but different applied filters, download only the features that match either layer1 or layer2 filter and not all the features from the datasource.
1 parent 6221ad5 commit 5eee86b

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

libqfieldsync/offliners.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,12 +403,13 @@ def _convert_to_offline_project(
403403
driver = ogr.GetDriverByName("GPKG")
404404
data_source = driver.CreateDataSource(offline_gpkg_path)
405405
datasource_mapping = self._get_datasource_mapping(project, offline_layers)
406+
filters_mapping = self._get_filters_mapping(datasource_mapping)
406407

407408
for layer_infos in datasource_mapping.values():
408409
layer_to_offline = layer_infos[0].layer
409410
self.create_layer(layer_to_offline, data_source, offline_gpkg_path)
410411

411-
for layer_infos in datasource_mapping.values():
412+
for datasource_hash, layer_infos in datasource_mapping.items():
412413
request = QgsFeatureRequest()
413414
# All layers for given `datasource_hash` are pointing to the very same file/datasource.
414415
# Here we get the first layer for convenience, but it doesn't really matter.
@@ -439,6 +440,9 @@ def _convert_to_offline_project(
439440
layer_bbox = tr.transform(bbox)
440441
request.setFilterRect(layer_bbox)
441442

443+
if filters_mapping[datasource_hash]:
444+
request.setFilterExpression(filters_mapping[datasource_hash])
445+
442446
source = self.convert_to_offline_layer(
443447
layer_to_offline, data_source, offline_gpkg_path, request
444448
)
@@ -465,6 +469,26 @@ def _convert_to_offline_project(
465469
project.writePath(offline_gpkg_path),
466470
)
467471

472+
def _get_filters_mapping(
473+
self, datasource_mapping: Dict[str, List[LayerInfo]]
474+
) -> Dict[str, str]:
475+
"""Get mapping of filter strings to be applied for each datasource. If no filters to be applied, the value will be an empty string."""
476+
filters_by_datasource = {}
477+
478+
for datasource_hash, layer_infos in datasource_mapping.items():
479+
filters = []
480+
for layer_info in layer_infos:
481+
if layer_info.subset_string.strip():
482+
filters.append(f"({layer_info.subset_string})")
483+
else:
484+
# if there is no subset string, we don't need to apply any filter, as it means "all features"
485+
filters = []
486+
break
487+
488+
filters_by_datasource[datasource_hash] = " OR ".join(filters)
489+
490+
return filters_by_datasource
491+
468492
def _get_datasource_mapping(
469493
self,
470494
project: QgsProject,

0 commit comments

Comments
 (0)