feat(platform): add replaceable geozone data layer

This commit is contained in:
Codex
2026-07-20 21:48:27 +03:00
parent 8a7465cf0e
commit 3446f3edc2
31 changed files with 1342 additions and 128 deletions
@@ -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-"));