Skip to contents

A track recorded by Mergin Maps is anonymous: the layer carries when, how far and who walked it, and nothing that says what the session was - a reach walk, a bushwhack, the drive in. This adds the columns that let the person who walked it name it in the field, rather than reconstructing it off a map weeks later.

Usage

rfp_tracking_fields_add(gpkg, fields = NULL, table = .rfp_tracking_table)

Arguments

gpkg

Character. Path to tracking_layer.gpkg.

fields

NULL (default) for the shipped set, or a data frame with field, type, widget, alias, options and default.

table

Character. Table inside the GeoPackage.

Value

Invisibly, a character vector of the fields added - empty when every one was already present.

Details

The GeoPackage half. rfp_qgs_tracking_fields_add() is the project half, and both are needed: a column with no widget is invisible in the app.

fieldwidget
track_nametextwhat the session was
track_typevalue mapreach walk, bushwhack, access route, drive, other
named_bytextdefaults to @mergin_username - who named it, where that differs from who walked it

Why adding a column is safe

The schema is fixed by the app, so augmenting it looks reckless. Measured against the installed plugin (Mergin 2024.2):

  • create_tracking_layer() has exactly one invocation, inside ProjectSettings.setup_tracking(), and it is reached only when the project's PositionTracking/TrackingLayer entry is empty or names a layer the project does not have. rfp_qgs_tracking_add() writes that entry, so the branch is unreachable for an rfp project - opening the plugin's settings dialog takes the other arm, which sets layer flags and returns.

  • Even on that branch nothing is overwritten: get_unique_filename() would write tracking_layer_1.gpkg beside the existing file.

  • setup_tracking_layer() assigns defaults through indexFromName(), one lookup per known field. It never enumerates or prunes, so an extra column is invisible to it.

That claim covers the desktop plugin, which is the only half readable from here; the mobile app is a separate codebase. It is also a moving target, so test-rfp_tracking.R asserts the call-site count against the installed plugin's own source rather than against this paragraph - an upstream release that added a reconcile path would take these columns, and everything typed into them, silently.

What it will not do

ALTER TABLE ... ADD COLUMN only. A column that already exists is skipped, so the call is idempotent and safe to re-run against a project in the field. A column that exists with a different declared type is an error rather than a repair: SQLite has no ALTER COLUMN TYPE, and the only route through is a table rebuild that destroys the rtree index, its 18 triggers, and every recorded session.

Examples

p <- file.path(tempdir(), "tracking_layer.gpkg")
rfp_tracking_layer_create(p, overwrite = TRUE)
rfp_tracking_fields_add(p)
#>  Added 4 fields to "tracking_layer": track_name, track_type, track_description, and named_by
names(sf::st_read(p, quiet = TRUE))
#> [1] "tracking_start_time" "tracking_end_time"   "total_distance"     
#> [4] "tracked_by"          "track_name"          "track_type"         
#> [7] "track_description"   "named_by"            "geom"               

# Idempotent - a second call adds nothing.
rfp_tracking_fields_add(p)
#>  All 4 tracking fields already present.