feat(mapping): centralize domain <-> contracts mappings (B5)
New @umt/mapping (depends on domain + contracts only): download status + pause reason, evidence level / media kind, identity resolution status, slot status / spec columns / evaluation, ParsedRelease <-> source_release.parsed, SiteRelease <-> source_release, PathBinding, OrganizePlan -> organization_record / file results / organize.plan output. Tables are Record<union, ...> so adding a value on either side fails typecheck or tests. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
da8e53bbca
commit
42ecc93fa5
16 files changed
+1282
-1
No files matched your search
@@ -0,0 +1,72 @@
|
||||
import type { ContentType as ContractContentType, Segment as ContractSegment, JsonObject } from "@umt/contracts";
|
||||
import {
|
||||
type ContentType as DomainContentType,
|
||||
type Segment as DomainSegment,
|
||||
PARSER_VERSION,
|
||||
type ParsedRelease,
|
||||
} from "@umt/domain";
|
||||
|
||||
// 标题解析结果 ↔ source_release.parsed / parser_version 列;综艺内容类型与分段 ↔ content_unit 列。
|
||||
|
||||
/** ParsedRelease → source_release 的 parsed(jsonb)与 parser_version(text) */
|
||||
export function toParsedColumns(p: ParsedRelease): { parsed: JsonObject; parserVersion: string } {
|
||||
return { parsed: JSON.parse(JSON.stringify(p)) as JsonObject, parserVersion: String(p.parserVersion) };
|
||||
}
|
||||
|
||||
const REQUIRED_ARRAYS = ["audio", "hdr", "variantTags", "explicitIds", "evidence"] as const;
|
||||
|
||||
/**
|
||||
* source_release 列 → ParsedRelease。版本不是当前 PARSER_VERSION 或形状不对时返回 null,
|
||||
* 调用方应按原标题重新解析(规则变化后旧结果作废)。
|
||||
*/
|
||||
export function fromParsedColumns(cols: { parsed: JsonObject; parserVersion: string | null }): ParsedRelease | null {
|
||||
if (cols.parserVersion !== String(PARSER_VERSION)) return null;
|
||||
const p = cols.parsed;
|
||||
if (p.parserVersion !== PARSER_VERSION || typeof p.raw !== "string" || typeof p.isEncode !== "boolean") return null;
|
||||
if (typeof p.contentType !== "string" || typeof p.confidence !== "string") return null;
|
||||
if (REQUIRED_ARRAYS.some((k) => !Array.isArray(p[k]))) return null;
|
||||
return p as unknown as ParsedRelease;
|
||||
}
|
||||
|
||||
const CONTENT_TYPE: Record<DomainContentType, ContractContentType> = {
|
||||
unknown: "unknown",
|
||||
main: "main",
|
||||
extra: "extra",
|
||||
behind_the_scenes: "behind_the_scenes",
|
||||
performance_only: "performance_only",
|
||||
preview: "preview",
|
||||
reaction: "reaction",
|
||||
};
|
||||
const CONTENT_TYPE_BACK: Record<ContractContentType, DomainContentType> = {
|
||||
main: "main",
|
||||
extra: "extra",
|
||||
behind_the_scenes: "behind_the_scenes",
|
||||
performance_only: "performance_only",
|
||||
preview: "preview",
|
||||
reaction: "reaction",
|
||||
unknown: "unknown",
|
||||
};
|
||||
export const DOMAIN_CONTENT_TYPES = Object.keys(CONTENT_TYPE) as DomainContentType[];
|
||||
|
||||
export const toContractContentType = (t: DomainContentType): ContractContentType => CONTENT_TYPE[t];
|
||||
export const toDomainContentType = (t: ContractContentType): DomainContentType => CONTENT_TYPE_BACK[t];
|
||||
|
||||
const SEGMENT: Record<DomainSegment, ContractSegment> = {
|
||||
full: "full",
|
||||
upper: "upper",
|
||||
middle: "middle",
|
||||
lower: "lower",
|
||||
};
|
||||
const SEGMENT_BACK: Record<ContractSegment, DomainSegment | undefined> = {
|
||||
full: "full",
|
||||
upper: "upper",
|
||||
middle: "middle",
|
||||
lower: "lower",
|
||||
// domain 用"字段缺失"表示未知
|
||||
unknown: undefined,
|
||||
};
|
||||
export const DOMAIN_SEGMENTS = Object.keys(SEGMENT) as DomainSegment[];
|
||||
|
||||
/** 解析结果没有分段信息(undefined)时落为 unknown */
|
||||
export const toContractSegment = (s: DomainSegment | undefined): ContractSegment => (s ? SEGMENT[s] : "unknown");
|
||||
export const toDomainSegment = (s: ContractSegment): DomainSegment | undefined => SEGMENT_BACK[s];
|
||||
Reference in new issue
Block a user