| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- namespace Admin.NET.Plugin.AiDOP.DataPlatform;
- /// <summary>
- /// 数据中台 stg → std transform 层的 JSON 取值 SQL 表达式生成器(跨源类型兼容)。
- ///
- /// 背景:SQL Server 源经 <c>MdpDbPullExecutor</c> 的 <c>System.Text.Json</c> 序列化后,raw_data JSON 与 MySQL 源不一致:
- /// datetime → ISO-8601 <c>2026-07-29T00:00:00</c>(T 分隔);bit → JSON boolean <c>true/false</c>;
- /// JSON null → <c>JSON_UNQUOTE</c> 后为字符串 <c>'null'</c>。MySQL STRICT 模式下裸 CAST/STR_TO_DATE 会 500。
- ///
- /// 本类<b>只生成 MySQL transform SQL 表达式字符串</b>,供调用方内插进 INSERT...SELECT;
- /// <b>不改 raw_data、不改 MdpDbPullExecutor/MdpStagingWriter/MdpSourceScopeFactory 核心、不改已运行 entity 的入站行为</b>。
- /// 属业务转换辅助,非核心 MDP 修改。字段名 field 为编译期常量,非用户输入,无注入风险。
- /// </summary>
- internal static class MdpJsonSql
- {
- /// <summary>裸取值:JSON_UNQUOTE(JSON_EXTRACT(alias.raw_data,'$.field'))。</summary>
- private static string Ext(string alias, string field) =>
- $"JSON_UNQUOTE(JSON_EXTRACT({alias}.raw_data,'$.{field}'))";
- /// <summary>可空字符串:把 JSON null 的 'null' 字符串归一为 SQL NULL。</summary>
- public static string Str(string alias, string field) =>
- $"NULLIF({Ext(alias, field)},'null')";
- /// <summary>秒级 datetime:兼容空格/ISO-T/带毫秒,NULL/空/'null' → NULL。</summary>
- public static string DateTimeSec(string alias, string field) =>
- $"STR_TO_DATE(REPLACE(LEFT(NULLIF(NULLIF({Ext(alias, field)},'null'),''),19),'T',' '),'%Y-%m-%d %H:%i:%s')";
- /// <summary>可空 DECIMAL:'null'/空 → NULL,避免 CAST('null' AS DECIMAL) STRICT 500。</summary>
- public static string Dec(string alias, string field, int p, int s) =>
- $"CAST(NULLIF(NULLIF({Ext(alias, field)},'null'),'') AS DECIMAL({p},{s}))";
- /// <summary>可空整数:'null'/空 → NULL。</summary>
- public static string Int(string alias, string field) =>
- $"CAST(NULLIF(NULLIF({Ext(alias, field)},'null'),'') AS SIGNED)";
- /// <summary>布尔判真:兼容 1/0 与 SQL Server bit 序列化的 true/false。</summary>
- public static string BoolTrue(string alias, string field) =>
- $"LOWER({Ext(alias, field)}) IN ('1','true')";
- /// <summary>原样取值(不做 'null' 归一):仅用于确知非空/仅展示的场景。</summary>
- public static string Raw(string alias, string field) => Ext(alias, field);
- /// <summary>raw_data.tenant_id 正整数解析 CASE 片段。</summary>
- public static string RawTenantCase(string alias) =>
- $"CASE WHEN JSON_UNQUOTE(JSON_EXTRACT({alias}.raw_data,'$.tenant_id')) REGEXP '^[0-9]+$' " +
- $"THEN CAST(JSON_UNQUOTE(JSON_EXTRACT({alias}.raw_data,'$.tenant_id')) AS SIGNED) END";
- /// <summary>stg 行租户:物理列 NULLIF 去 0 → raw_data;解析不到返回 NULL。
- /// 调用方必须在 WHERE 里用 <see cref="TenantGuard"/> 跳过该行,禁止用 0 兜底。</summary>
- public static string TenantFromStg(string alias) =>
- $"COALESCE(NULLIF({alias}.tenant_id, 0), {RawTenantCase(alias)})";
- /// <summary>stg 行租户:物理列/json → 上下文参数;解析不到返回 NULL。</summary>
- public static string TenantFromStg(string alias, string ctxParam) =>
- $"COALESCE(NULLIF({alias}.tenant_id, 0), NULLIF({ctxParam}, 0), {RawTenantCase(alias)})";
- /// <summary>stg 行租户:JSON 列表达式 + 物理列 + raw_data;解析不到返回 NULL。</summary>
- public static string TenantFromStgJsonCol(string alias, string jsonColExpr) =>
- $"COALESCE(NULLIF({jsonColExpr}, 0), NULLIF({alias}.tenant_id, 0), {RawTenantCase(alias)})";
- /// <summary>WHERE 守卫:与上面三个方法配对使用,跳过租户解析不到的行。
- /// 传入的必须是同一个租户表达式字符串,否则守卫与取值不一致。</summary>
- public static string TenantGuard(string tenantExpr) => $"({tenantExpr}) IS NOT NULL";
- }
|