feat(geo): auto-derive geometry из data.lat/lon + backfill migration
Записи ground_station и similar dicts имеют lat/lon в data, но geometryWkt не задан. Spatial filter (AOI) WHERE geometry IS NOT NULL AND ST_Intersects(...) возвращал 0 records даже когда координаты есть. Три места починены: 1. DictionaryRecordService.resolveGeometry — для CRUD через REST. Если req.geometryWkt() задан — приоритет (explicit). Иначе читаем data.lat/lon (или latitude/longitude/lng), валидируем ranges, строим POINT(lon lat) с SRID 4326. Игнор out-of-range без throw — не ломаем legacy data. 2. CuodBundleImporter.deriveLatLonGeometry — bundle bypass'ит service, reuse'аем ту же логику локально (5 строк inline). Применяется при создании НОВЫХ records (existing skipped по businessKey). 3. Liquibase migration 0015-backfill-latlon-geometry — UPDATE existing records где geometry IS NULL AND data has lat/lon. Три changeset'а для разных aliases (lat/lon, latitude/longitude, lat/lng). Idempotent (только NULL→value), rollback supported (NULL обратно). После deploy: existing 3 ground_station записей (Отрадное и др.) и spacecraft с lat/lon получат POINT geometry. AOI bbox-фильтр заработает.
This commit is contained in:
+99
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.27.xsd">
|
||||
|
||||
<!--
|
||||
Backfill geometry для existing записей где data содержит lat/lon
|
||||
(или latitude/longitude или lng), но geometry IS NULL. Match'ит
|
||||
backend auto-derive в DictionaryRecordService.resolveGeometry +
|
||||
CuodBundleImporter.deriveLatLonGeometry — bundle import skip'ит
|
||||
existing records, поэтому уже-загруженные записи остались без
|
||||
geometry. Без этой миграции AOI spatial filter возвращает 0 records
|
||||
на ground_station и similar dictionaries.
|
||||
|
||||
Idempotent: только WHERE geometry IS NULL. Permission to fail per row
|
||||
ON_ERROR=CONTINUE — некоторые записи могут иметь lat/lon как string
|
||||
или вне диапазона; пропускаем, не падаем на всю миграцию.
|
||||
|
||||
Rollback: SET geometry = NULL для тех же rows (lossless если
|
||||
geometry была null до).
|
||||
-->
|
||||
<changeSet id="0015-backfill-latlon-geometry-lat-lon" author="ordinis">
|
||||
<comment>Backfill geometry из data.lat + data.lon</comment>
|
||||
<sql>
|
||||
UPDATE dictionary_records
|
||||
SET geometry = ST_SetSRID(
|
||||
ST_MakePoint(
|
||||
(data->>'lon')::double precision,
|
||||
(data->>'lat')::double precision),
|
||||
4326)
|
||||
WHERE geometry IS NULL
|
||||
AND jsonb_typeof(data->'lat') = 'number'
|
||||
AND jsonb_typeof(data->'lon') = 'number'
|
||||
AND (data->>'lat')::double precision BETWEEN -90 AND 90
|
||||
AND (data->>'lon')::double precision BETWEEN -180 AND 180;
|
||||
</sql>
|
||||
<rollback>
|
||||
<sql>
|
||||
UPDATE dictionary_records
|
||||
SET geometry = NULL
|
||||
WHERE jsonb_typeof(data->'lat') = 'number'
|
||||
AND jsonb_typeof(data->'lon') = 'number';
|
||||
</sql>
|
||||
</rollback>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0015-backfill-latlon-geometry-latitude-longitude" author="ordinis">
|
||||
<comment>Backfill geometry из data.latitude + data.longitude (alias)</comment>
|
||||
<sql>
|
||||
UPDATE dictionary_records
|
||||
SET geometry = ST_SetSRID(
|
||||
ST_MakePoint(
|
||||
(data->>'longitude')::double precision,
|
||||
(data->>'latitude')::double precision),
|
||||
4326)
|
||||
WHERE geometry IS NULL
|
||||
AND jsonb_typeof(data->'latitude') = 'number'
|
||||
AND jsonb_typeof(data->'longitude') = 'number'
|
||||
AND (data->>'latitude')::double precision BETWEEN -90 AND 90
|
||||
AND (data->>'longitude')::double precision BETWEEN -180 AND 180;
|
||||
</sql>
|
||||
<rollback>
|
||||
<sql>
|
||||
UPDATE dictionary_records
|
||||
SET geometry = NULL
|
||||
WHERE jsonb_typeof(data->'latitude') = 'number'
|
||||
AND jsonb_typeof(data->'longitude') = 'number';
|
||||
</sql>
|
||||
</rollback>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0015-backfill-latlon-geometry-lat-lng" author="ordinis">
|
||||
<comment>Backfill geometry из data.lat + data.lng (alternate alias)</comment>
|
||||
<sql>
|
||||
UPDATE dictionary_records
|
||||
SET geometry = ST_SetSRID(
|
||||
ST_MakePoint(
|
||||
(data->>'lng')::double precision,
|
||||
(data->>'lat')::double precision),
|
||||
4326)
|
||||
WHERE geometry IS NULL
|
||||
AND jsonb_typeof(data->'lat') = 'number'
|
||||
AND jsonb_typeof(data->'lng') = 'number'
|
||||
AND (data->>'lat')::double precision BETWEEN -90 AND 90
|
||||
AND (data->>'lng')::double precision BETWEEN -180 AND 180;
|
||||
</sql>
|
||||
<rollback>
|
||||
<sql>
|
||||
UPDATE dictionary_records
|
||||
SET geometry = NULL
|
||||
WHERE jsonb_typeof(data->'lat') = 'number'
|
||||
AND jsonb_typeof(data->'lng') = 'number';
|
||||
</sql>
|
||||
</rollback>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -24,5 +24,6 @@
|
||||
<include file="changes/0012-audit-log-ipaddress-varchar.xml" relativeToChangelogFile="true"/>
|
||||
<include file="changes/0013-webhook-subscriptions.xml" relativeToChangelogFile="true"/>
|
||||
<include file="changes/0014-webhook-deliveries.xml" relativeToChangelogFile="true"/>
|
||||
<include file="changes/0015-backfill-latlon-geometry.xml" relativeToChangelogFile="true"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
||||
Reference in New Issue
Block a user