feat(import): term 物化与缺失自建
Plan 3 Task 2:createTermWriter 管道写入器——双源物化分类域。 - wp:term 事件:taxonomies(key→object_type 映射 + public_base_path 前置事实 9 常量)+ terms(source_id=term_id 字符串) - row 的 taxonomyRefs miss 时自建(source_id=auto:<nicename>、slug=nicename; phase2-smoke 实证真实 WXR 的 wp:term 表缺 category/post_tag 整域);同 nicename 多次引用只建一条(内存 (taxonomy,slug) 索引 + UNIQUE 兜底) - 单遍流式 + 收编:WXR 文档序 items 先于 wp:term——row 先到自建、wp:term 后到 就地 UPDATE 扶正 source_id/name,两种顺序终态一致(测试钉死顺序无关性) - content_terms:is_primary 每 (entry, taxonomy) 首个 true 余 false(WP 单主分类 近似);row 无 content entry → term 仍物化、关联跳过 + issue(禁静默) - ctx 加法扩展 events: AsyncIterable<AdapterEvent>(测试手构注入,Task 6 接真流) - Task 1 遗留两行:ImportErrorCode 补 REPORT_WRITE_FAILED、ctx.db 事务边界 JSDoc Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ import {
|
||||
MAPPING_VERSION,
|
||||
PARSER_VERSION,
|
||||
SANITIZER_VERSION,
|
||||
type AdapterEvent,
|
||||
} from '@sf/adapter-wp'
|
||||
import { importJobs, sites, sourceConnections, sourceSnapshots } from '../../db/schema.js'
|
||||
import type * as schema from '../../db/schema.js'
|
||||
@@ -51,6 +52,7 @@ export type ImportErrorCode =
|
||||
| 'SNAPSHOT_NOT_FOUND'
|
||||
| 'NO_WXR_SNAPSHOT'
|
||||
| 'PIPELINE_FAILED'
|
||||
| 'REPORT_WRITE_FAILED'
|
||||
|
||||
/** 导入失败(可预期错误):CLI 以 code 区分呈现;不裹程序 bug(那些原样上抛) */
|
||||
export class ImportError extends Error {
|
||||
@@ -83,6 +85,11 @@ export interface SnapshotRef {
|
||||
|
||||
/** 管道执行上下文:Task 6 真实管道的全部输入(站点 locale 接缝见前置事实 8) */
|
||||
export interface ImportJobContext {
|
||||
/**
|
||||
* 写入器自行管理事务:ctx.db 为直连(非事务代理),需要原子性的多语句写入用
|
||||
* db.transaction 自行包裹;单语句 upsert(on conflict do nothing/update)本身原子,
|
||||
* 无需显式事务。
|
||||
*/
|
||||
db: ImportDb
|
||||
jobId: string
|
||||
siteId: string
|
||||
@@ -100,6 +107,13 @@ export interface ImportJobContext {
|
||||
* ctx.report.issues.push(...))。合并规则见 {@link ImportPipeline}——返回值优先。
|
||||
*/
|
||||
report: ImportPipelineOutcome
|
||||
/**
|
||||
* 适配器事件流(runWxrAdapter 产物:row/unsupported/error/term 按文档序交错)。
|
||||
* Task 2 加法扩展:测试经 {@link CreateImportJobInput.events} 手构注入;Task 6 编排
|
||||
* 时改为从 wxr 快照构造真流(runWxrAdapter(storagePath 流))——多个写入器共享同流
|
||||
* 时的重迭代策略(每写入器一新生成器等)由 Task 6 决定,本字段只承诺"可迭代一次"。
|
||||
*/
|
||||
events: AsyncIterable<AdapterEvent>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,6 +144,12 @@ export interface CreateImportJobInput {
|
||||
connectionName?: string
|
||||
/** 报告根(落 <reportRoot>/<jobId>/reports/import.json);缺省 repoRoot/artifacts/import */
|
||||
reportRoot?: string
|
||||
/**
|
||||
* 适配器事件流(ctx.events 的注入位):Task 2 测试手构注入;缺省空流(空管道下无消费
|
||||
* 方)。Task 6 编排时由此改为从 wxr 快照构造 runWxrAdapter 真流(前置事实 8:mapConfig
|
||||
* .locale 必须传 site.default_locale)。
|
||||
*/
|
||||
events?: AsyncIterable<AdapterEvent>
|
||||
/** 管道钩子(测试/Task 6 注入);缺省空管道 */
|
||||
pipeline?: ImportPipeline
|
||||
}
|
||||
@@ -344,7 +364,7 @@ export async function createImportJob(
|
||||
|
||||
// 阶段 5:管道(本任务缺省空管道;Task 6 接真实写入器)——抛错 → failed 终态。
|
||||
// 产出汇合规则(ImportPipeline JSDoc 钉死):返回值 counts 覆盖累加器同名键、issues 追加在后。
|
||||
let failed: { code: string; summary: string } | null = null
|
||||
let failed: { code: ImportErrorCode; summary: string } | null = null
|
||||
const ctx: ImportJobContext = {
|
||||
db,
|
||||
jobId,
|
||||
@@ -357,6 +377,7 @@ export async function createImportJob(
|
||||
manualUrlListSnapshot,
|
||||
versions: VERSIONS,
|
||||
report: { counts: {}, issues: [] },
|
||||
events: input.events ?? emptyEvents(),
|
||||
}
|
||||
let outcome: ImportPipelineOutcome | null = null
|
||||
try {
|
||||
@@ -497,3 +518,7 @@ function slimRef(ref: SnapshotRef): {
|
||||
async function emptyPipeline(_ctx: ImportJobContext): Promise<ImportPipelineOutcome> {
|
||||
return { counts: {}, issues: [] }
|
||||
}
|
||||
|
||||
/** 缺省空事件流(input.events 缺席时的 ctx.events 占位;每次调用产新迭代器) */
|
||||
async function* emptyEvents(): AsyncGenerator<AdapterEvent, void, void> {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user