Skip to main content

Synchronizing External Data

The Integration Challenge: The Shelf Origin Pattern to Respect Single Source of Truth

Updated over a month ago

The ShelfOrigin property is designed for handling external data, but it requires explanation to be used correctly.

  • Your database has a Unit with ID GUID-A.

  • ResQueServe assigns it ID 105.

  • How do you know that 105 corresponds to GUID-A next time you run an update?

You could save the ResQueServe ID back to your database, but that is brittle or you even can't because you don't own the database. Instead, ResQueServe solves this with the Shelf Origin Pattern.


What is a "Shelf Origin"?

Every major entity in the ResQueServe ecosystem (Unit, Poi, Keyword) implements the IShelf interface, which contains an Origin property. This property allows you to stamp your system's metadata directly onto the ResQueServe object.

The Data Structure

The ShelfOrigin is polymorphic. It accepts a Namespace (who owns the data), an ID (the external key), and an optional Version.

C#

// The Abstract Base
public abstract record ShelfOriginBase { ... }

// The Concrete Implementation
public record ShelfOrigin<T>(
string Namespace,
string Id,
ShelfVersion<T>? Version
);

Property

Purpose

Example

Namespace

Identifies the source system. Prevents collisions if you import from both SAP and OpenStreetMap.

"Internal_HR", "OSM"

Id

The unique key in the source system.

"EMP-8821", "node/1293"

Version

Used for Delta Updates. Supports int, long, Guid, or DateTimeOffset.

2023-10-25, v5


Implementation Guide: The "Upsert" Workflow

Here is how to write a robust synchronization job that pushes data from your local CSV/DB to ResQueServe without creating duplicates.

Step 1: Define your Origin

Always use a consistent Namespace constant.

C#

const string MySource = "MyLegacyDatabase";

Step 2: Create Entities with Origins

When creating a new object, attach the origin info.

C#

var newUnit = new Unit
{
Callsign = "Rescue 1",
// ... other properties ...

// Attach external metadata
Origin = new ShelfOrigin<DateTimeOffset>(
Namespace: MySource,
Id: "LOCAL_DB_ID_99",
Version: new ShelfVersion<DateTimeOffset>(DateTimeOffset.UtcNow)
)
};

await unitClient.CreateAsync(dpcId, newUnit);

Step 3: Syncing & Updating (The "Smart Update")

When your sync job runs again, you don't want to blindly overwrite everything. You can use the Version field to detect changes.

C#

public async Task SyncFleet(long dpcId, List<MyLocalUnit> localUnits)
{
// 1. Fetch all existing units from ResQueServe
// (Using pagination to get the full list)
var remoteUnits = await FetchAllRemoteUnits(dpcId);

foreach (var localUnit in localUnits)
{
// 2. Find if this unit already exists in ResQueServe by checking the Origin
var match = remoteUnits.FirstOrDefault(u =>
u.Origin is ShelfOrigin<DateTimeOffset> origin &&
origin.Namespace == MySource &&
origin.Id == localUnit.LocalId
);

if (match == null)
{
// CREATE: It doesn't exist yet
await CreateUnitAsync(localUnit);
}
else
{
// UPDATE: Check if it needs updating
// Cast the origin to the specific generic type we used
var origin = (ShelfOrigin<DateTimeOffset>)match.Origin;

// If local data is newer than the remote data
if (localUnit.LastModified > origin.Version.Value)
{
await UpdateUnitAsync(match.Id, localUnit);
}
}
}
}

Working with Third-Party Data (e.g., OpenStreetMap)

If you are building a plugin that enriches ResQueServe with public data (like importing Fire Stations from OSM), the Shelf Origin is mandatory to respect the "Single Source of Truth."

Example JSON for an OSM Import:

JSON

{
"name": "Fire Station 1",
"category": 14,
"origin": {
"namespace": "OpenStreetMap",
"id": "way/4522910",
"version": "5"
}
}
  • Do not store ResQueServe IDs in your external database if you can avoid it.

  • Do use ShelfOrigin to store your IDs inside ResQueServe.

  • Do use the Version generic to implement efficient "Delta Updates," saving bandwidth and API calls.

Did this answer your question?