feat(platform): add replaceable geozone data layer
This commit is contained in:
@@ -205,6 +205,54 @@ try {
|
||||
(error) => error?.status === 400 && error?.code === "data_product_history_cursor_invalid",
|
||||
);
|
||||
|
||||
const zoneDefinition = normalizeDataProductDefinition({
|
||||
id: "test.zones.current.v1",
|
||||
version: "1.0.0",
|
||||
ontologyRevision: "ontology.map.zone.v1",
|
||||
deliveryMode: "snapshot+patch",
|
||||
semanticTypes: ["map.zone"],
|
||||
fields: ["display_name", "geometry", "geometry_kind", "source_kind", "source_revision"],
|
||||
fieldContracts: {
|
||||
display_name: { type: "string", required: true },
|
||||
geometry: { type: "geometry", required: true },
|
||||
geometry_kind: { type: "string", required: true, enum: ["polygon"] },
|
||||
source_kind: { type: "string", required: true, enum: ["live_api", "versioned_snapshot"] },
|
||||
source_revision: { type: "string", required: true },
|
||||
},
|
||||
history: { mode: "none", retentionDays: 1 },
|
||||
});
|
||||
await persistDataProductDefinition(pool, zoneDefinition);
|
||||
const storedZoneDefinition = await loadDataProductDefinition(pool, zoneDefinition.id);
|
||||
const zoneBinding = { ...binding, allowedDataProductIds: [zoneDefinition.id] };
|
||||
const firstZoneGenerationAt = "2026-07-15T10:10:00.000Z";
|
||||
const firstZoneGeneration = await persistDataProductPublish(
|
||||
pool,
|
||||
zoneBatch("zones-01", firstZoneGenerationAt, [zoneFact("zone-01", firstZoneGenerationAt), zoneFact("zone-02", firstZoneGenerationAt)]),
|
||||
storedZoneDefinition,
|
||||
);
|
||||
assert.equal(firstZoneGeneration.currentUpdatedCount, 2);
|
||||
assert.equal(firstZoneGeneration.currentRemovedCount, 0);
|
||||
const secondZoneGenerationAt = "2026-07-15T10:11:00.000Z";
|
||||
const secondZoneGeneration = await persistDataProductPublish(
|
||||
pool,
|
||||
zoneBatch("zones-02", secondZoneGenerationAt, [zoneFact("zone-01", secondZoneGenerationAt)]),
|
||||
storedZoneDefinition,
|
||||
);
|
||||
assert.equal(secondZoneGeneration.currentUpdatedCount, 1);
|
||||
assert.equal(secondZoneGeneration.currentRemovedCount, 1);
|
||||
assert.equal(secondZoneGeneration.patchOperationCount, 2);
|
||||
const zoneSnapshot = await readDataProductSnapshot(pool, zoneBinding, storedZoneDefinition);
|
||||
assert.equal(validateDataProductSnapshot(zoneSnapshot).ok, true);
|
||||
assert.deepEqual(zoneSnapshot.facts.map((value) => value.sourceId), ["zone-01"]);
|
||||
assert.equal(zoneSnapshot.facts[0].geometry.type, "Polygon");
|
||||
const zonePatches = await readPatchEvents(pool, zoneBinding, storedZoneDefinition, 0n);
|
||||
assert.equal(zonePatches.every((value) => validateDataProductPatch(value).ok), true);
|
||||
assert.equal(zonePatches.flatMap((value) => value.operations).some((value) => value.op === "remove" && value.sourceId === "zone-02"), true);
|
||||
await assert.rejects(
|
||||
persistDataProductPublish(pool, zoneBatch("zones-stale", firstZoneGenerationAt, [zoneFact("zone-01", firstZoneGenerationAt)]), storedZoneDefinition),
|
||||
(error) => error?.status === 409 && error?.code === "data_product_generation_not_newer",
|
||||
);
|
||||
|
||||
console.log("external-data-plane delivery integration: ok");
|
||||
} finally {
|
||||
await pool.end();
|
||||
@@ -233,3 +281,38 @@ function fact(sourceId, longitude, latitude, status, observedAt = "2026-07-15T10
|
||||
geometry: { type: "Point", coordinates: [longitude, latitude] },
|
||||
};
|
||||
}
|
||||
|
||||
function zoneBatch(runId, generationAt, facts) {
|
||||
return {
|
||||
schemaVersion: "nodedc.external-provider-contract/v1",
|
||||
source: { tenantId: "tenant-test", connectionId: "connection-test", providerId: "provider-test" },
|
||||
contract: { dataProductId: "test.zones.current.v1", ontologyRevision: "ontology.map.zone.v1", version: "1.0.0" },
|
||||
batch: {
|
||||
runId,
|
||||
sequence: 0,
|
||||
idempotencyKey: `${runId}.chunk-0`,
|
||||
receivedAt: generationAt,
|
||||
mode: "replace",
|
||||
generationAt,
|
||||
},
|
||||
facts,
|
||||
};
|
||||
}
|
||||
|
||||
function zoneFact(sourceId, observedAt) {
|
||||
return {
|
||||
sourceId,
|
||||
semanticType: "map.zone",
|
||||
observedAt,
|
||||
attributes: {
|
||||
display_name: sourceId,
|
||||
geometry_kind: "polygon",
|
||||
source_kind: "live_api",
|
||||
source_revision: "gelios-rest-v1",
|
||||
},
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [[[37.60, 55.74], [37.62, 55.74], [37.62, 55.76], [37.60, 55.74]]],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ assert.deepEqual(bundled.map((definition) => definition.id), [
|
||||
"fleet.positions.current.v2",
|
||||
"fleet.positions.current.v3",
|
||||
"fleet.positions.current.v4",
|
||||
"map.zones.current.v1",
|
||||
]);
|
||||
assert.deepEqual(bundled[0].semanticTypes, ["map.moving_object"]);
|
||||
assert.equal(bundled[0].ontologyRevision, "ontology.map.moving_object.v1");
|
||||
@@ -45,6 +46,10 @@ assert.deepEqual(bundled[3].fieldContracts.movement_state, {
|
||||
required: true,
|
||||
enum: ["moving", "stopped"],
|
||||
});
|
||||
assert.equal(bundled[4].version, "1.0.0");
|
||||
assert.equal(bundled[4].ontologyRevision, "ontology.map.zone.v1");
|
||||
assert.deepEqual(bundled[4].semanticTypes, ["map.zone"]);
|
||||
assert.deepEqual(bundled[4].fieldContracts.geometry, { type: "geometry", required: true });
|
||||
assert.equal(Object.keys(bundled[3].fieldContracts).length, bundled[3].fields.length);
|
||||
|
||||
const directory = await mkdtemp(join(tmpdir(), "nodedc-edp-definitions-"));
|
||||
|
||||
Reference in New Issue
Block a user