Stage 1: standardize delivery field names
This commit is contained in:
@@ -27,6 +27,16 @@ class FieldValueRule:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class FieldNameRule:
|
||||||
|
field_name_jp: str
|
||||||
|
field_name_std: str
|
||||||
|
field_group_name: str
|
||||||
|
keep_in_delivery: bool
|
||||||
|
keep_in_engineering: bool
|
||||||
|
normalization_class: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class RenderRule:
|
class RenderRule:
|
||||||
rule_id: str
|
rule_id: str
|
||||||
@@ -86,12 +96,14 @@ class NavSeaMappingRegistry:
|
|||||||
bundle_id: str,
|
bundle_id: str,
|
||||||
bundle_version: str,
|
bundle_version: str,
|
||||||
source_layer_rules: dict[str, dict[str, str]],
|
source_layer_rules: dict[str, dict[str, str]],
|
||||||
|
field_name_rules: dict[str, FieldNameRule],
|
||||||
field_value_rules: dict[tuple[str, str], list[FieldValueRule]],
|
field_value_rules: dict[tuple[str, str], list[FieldValueRule]],
|
||||||
render_rules: list[RenderRule],
|
render_rules: list[RenderRule],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.bundle_id = bundle_id
|
self.bundle_id = bundle_id
|
||||||
self.bundle_version = bundle_version
|
self.bundle_version = bundle_version
|
||||||
self.source_layer_rules = source_layer_rules
|
self.source_layer_rules = source_layer_rules
|
||||||
|
self.field_name_rules = field_name_rules
|
||||||
self.field_value_rules = field_value_rules
|
self.field_value_rules = field_value_rules
|
||||||
self.render_rules = render_rules
|
self.render_rules = render_rules
|
||||||
|
|
||||||
@@ -145,6 +157,32 @@ class NavSeaMappingRegistry:
|
|||||||
for row in cur.fetchall()
|
for row in cur.fetchall()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
SELECT
|
||||||
|
field_name_jp,
|
||||||
|
field_name_std,
|
||||||
|
field_group_name,
|
||||||
|
keep_in_delivery,
|
||||||
|
keep_in_engineering,
|
||||||
|
normalization_class
|
||||||
|
FROM navsea_field_name_rules
|
||||||
|
WHERE bundle_id = %s AND bundle_version = %s
|
||||||
|
""",
|
||||||
|
(resolved_bundle_id, resolved_bundle_version),
|
||||||
|
)
|
||||||
|
field_name_rules = {
|
||||||
|
str(row["field_name_jp"]): FieldNameRule(
|
||||||
|
field_name_jp=str(row["field_name_jp"]),
|
||||||
|
field_name_std=str(row["field_name_std"]),
|
||||||
|
field_group_name=str(row["field_group_name"]),
|
||||||
|
keep_in_delivery=bool(row["keep_in_delivery"]),
|
||||||
|
keep_in_engineering=bool(row["keep_in_engineering"]),
|
||||||
|
normalization_class=str(row["normalization_class"]),
|
||||||
|
)
|
||||||
|
for row in cur.fetchall()
|
||||||
|
}
|
||||||
|
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
@@ -200,6 +238,7 @@ class NavSeaMappingRegistry:
|
|||||||
bundle_id=resolved_bundle_id,
|
bundle_id=resolved_bundle_id,
|
||||||
bundle_version=resolved_bundle_version,
|
bundle_version=resolved_bundle_version,
|
||||||
source_layer_rules=source_layer_rules,
|
source_layer_rules=source_layer_rules,
|
||||||
|
field_name_rules=field_name_rules,
|
||||||
field_value_rules=field_value_rules,
|
field_value_rules=field_value_rules,
|
||||||
render_rules=render_rules,
|
render_rules=render_rules,
|
||||||
)
|
)
|
||||||
@@ -210,6 +249,9 @@ class NavSeaMappingRegistry:
|
|||||||
return source_layer_jp, f"SLR:{source_layer_jp}:identity"
|
return source_layer_jp, f"SLR:{source_layer_jp}:identity"
|
||||||
return rule["source_layer_std"], rule["source_layer_rule_id"]
|
return rule["source_layer_std"], rule["source_layer_rule_id"]
|
||||||
|
|
||||||
|
def get_field_name_rule(self, field_name: str) -> FieldNameRule | None:
|
||||||
|
return self.field_name_rules.get(field_name)
|
||||||
|
|
||||||
def standardize_field_value(
|
def standardize_field_value(
|
||||||
self,
|
self,
|
||||||
field_name_jp: str,
|
field_name_jp: str,
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ LIGHT_COLOR_REMARK_MAP = {
|
|||||||
"O": "orange",
|
"O": "orange",
|
||||||
"A": "amber",
|
"A": "amber",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class DbConfig:
|
class DbConfig:
|
||||||
host: str = "localhost"
|
host: str = "localhost"
|
||||||
@@ -144,6 +146,10 @@ def text_or_none(value: object) -> str | None:
|
|||||||
return text or None
|
return text or None
|
||||||
|
|
||||||
|
|
||||||
|
def contains_non_ascii(text: str) -> bool:
|
||||||
|
return any(ord(ch) > 127 for ch in text)
|
||||||
|
|
||||||
|
|
||||||
def parse_number(value: object) -> float | None:
|
def parse_number(value: object) -> float | None:
|
||||||
text = text_or_none(value)
|
text = text_or_none(value)
|
||||||
if not text:
|
if not text:
|
||||||
@@ -208,6 +214,7 @@ class NavSeaTileBuilder:
|
|||||||
workers: int,
|
workers: int,
|
||||||
all_tiles: bool,
|
all_tiles: bool,
|
||||||
engineering_mode: bool,
|
engineering_mode: bool,
|
||||||
|
strip_legacy_japanese_delivery: bool,
|
||||||
fid_codec: NavSeaFidCodec | None,
|
fid_codec: NavSeaFidCodec | None,
|
||||||
fid_key_id: str | None,
|
fid_key_id: str | None,
|
||||||
bundle_id: str | None,
|
bundle_id: str | None,
|
||||||
@@ -223,6 +230,7 @@ class NavSeaTileBuilder:
|
|||||||
self.workers = workers
|
self.workers = workers
|
||||||
self.all_tiles = all_tiles
|
self.all_tiles = all_tiles
|
||||||
self.engineering_mode = engineering_mode
|
self.engineering_mode = engineering_mode
|
||||||
|
self.strip_legacy_japanese_delivery = strip_legacy_japanese_delivery
|
||||||
self.fid_codec = fid_codec
|
self.fid_codec = fid_codec
|
||||||
self.fid_key_id = fid_key_id
|
self.fid_key_id = fid_key_id
|
||||||
self.bundle_id = bundle_id
|
self.bundle_id = bundle_id
|
||||||
@@ -473,7 +481,17 @@ class NavSeaTileBuilder:
|
|||||||
properties.update(chart_properties)
|
properties.update(chart_properties)
|
||||||
if self.engineering_mode:
|
if self.engineering_mode:
|
||||||
properties["trace_status"] = trace_status
|
properties["trace_status"] = trace_status
|
||||||
|
properties, field_name_unresolved = self.standardize_output_properties(
|
||||||
|
properties=properties,
|
||||||
|
source_layer=str(row["source_layer"]),
|
||||||
|
canonical_object_type=text_or_none(row["canonical_object_type"]) or "",
|
||||||
|
canonical_family=text_or_none(row["canonical_family"]) or "",
|
||||||
|
geom_type=str(source_feature.get("geometry", {}).get("type", "")),
|
||||||
|
feature_id=int(row["feature_id"]),
|
||||||
|
tile=job,
|
||||||
|
)
|
||||||
unresolved.extend(feature_unresolved)
|
unresolved.extend(feature_unresolved)
|
||||||
|
unresolved.extend(field_name_unresolved)
|
||||||
|
|
||||||
output_feature = {
|
output_feature = {
|
||||||
"geometry": source_feature["geometry"],
|
"geometry": source_feature["geometry"],
|
||||||
@@ -745,6 +763,63 @@ class NavSeaTileBuilder:
|
|||||||
|
|
||||||
return chart, unresolved, trace_status
|
return chart, unresolved, trace_status
|
||||||
|
|
||||||
|
def standardize_output_properties(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
properties: dict[str, object],
|
||||||
|
source_layer: str,
|
||||||
|
canonical_object_type: str,
|
||||||
|
canonical_family: str,
|
||||||
|
geom_type: str,
|
||||||
|
feature_id: int,
|
||||||
|
tile: TileJob,
|
||||||
|
) -> tuple[dict[str, object], list[dict]]:
|
||||||
|
normalized: dict[str, object] = {}
|
||||||
|
unresolved: list[dict] = []
|
||||||
|
|
||||||
|
for key, value in properties.items():
|
||||||
|
if key == "fid":
|
||||||
|
# By the time we normalize output properties, fid already means
|
||||||
|
# the NavSea public ID, not the original source fid field.
|
||||||
|
normalized[key] = value
|
||||||
|
continue
|
||||||
|
rule = self.mapping_registry.get_field_name_rule(str(key))
|
||||||
|
if rule is None:
|
||||||
|
normalized[key] = value
|
||||||
|
if (
|
||||||
|
not self.engineering_mode
|
||||||
|
and self.strip_legacy_japanese_delivery
|
||||||
|
and contains_non_ascii(str(key))
|
||||||
|
):
|
||||||
|
unresolved.append(
|
||||||
|
self.make_unresolved_event(
|
||||||
|
issue_type="field_name_unmapped",
|
||||||
|
reason="delivery output still contains an unmapped non-ASCII field name",
|
||||||
|
source_layer=source_layer,
|
||||||
|
canonical_object_type=canonical_object_type,
|
||||||
|
canonical_family=canonical_family,
|
||||||
|
geom_type=geom_type,
|
||||||
|
feature_id=feature_id,
|
||||||
|
tile=tile,
|
||||||
|
fid=properties.get("fid"),
|
||||||
|
field_name=str(key),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if self.engineering_mode:
|
||||||
|
if rule.keep_in_engineering:
|
||||||
|
normalized[key] = value
|
||||||
|
normalized[rule.field_name_std] = value
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not self.strip_legacy_japanese_delivery:
|
||||||
|
normalized[key] = value
|
||||||
|
if rule.keep_in_delivery:
|
||||||
|
normalized[rule.field_name_std] = value
|
||||||
|
|
||||||
|
return normalized, unresolved
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def make_unresolved_event(
|
def make_unresolved_event(
|
||||||
*,
|
*,
|
||||||
@@ -1302,6 +1377,11 @@ def parse_args() -> argparse.Namespace:
|
|||||||
parser.add_argument("--workers", type=int, default=4)
|
parser.add_argument("--workers", type=int, default=4)
|
||||||
parser.add_argument("--all-tiles", action="store_true")
|
parser.add_argument("--all-tiles", action="store_true")
|
||||||
parser.add_argument("--engineering", action="store_true")
|
parser.add_argument("--engineering", action="store_true")
|
||||||
|
parser.add_argument(
|
||||||
|
"--strip-legacy-japanese-delivery",
|
||||||
|
action="store_true",
|
||||||
|
help="drop mapped Japanese structural keys from delivery tiles after writing standardized aliases",
|
||||||
|
)
|
||||||
parser.add_argument("--fid-key")
|
parser.add_argument("--fid-key")
|
||||||
parser.add_argument("--fid-key-id", default="navsea-fid-key-v1")
|
parser.add_argument("--fid-key-id", default="navsea-fid-key-v1")
|
||||||
parser.add_argument("--bundle-id", default="navsea-reversible-v1")
|
parser.add_argument("--bundle-id", default="navsea-reversible-v1")
|
||||||
@@ -1338,6 +1418,7 @@ def main() -> None:
|
|||||||
workers=max(1, args.workers),
|
workers=max(1, args.workers),
|
||||||
all_tiles=args.all_tiles,
|
all_tiles=args.all_tiles,
|
||||||
engineering_mode=args.engineering,
|
engineering_mode=args.engineering,
|
||||||
|
strip_legacy_japanese_delivery=args.strip_legacy_japanese_delivery,
|
||||||
fid_codec=fid_codec,
|
fid_codec=fid_codec,
|
||||||
fid_key_id=args.fid_key_id,
|
fid_key_id=args.fid_key_id,
|
||||||
bundle_id=args.bundle_id,
|
bundle_id=args.bundle_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user