chore(db): 寄卖合并迁移顺延为 159,避开 main 的 152/158 编号

This commit is contained in:
2026-11-12 16:08:47 +08:00
parent 2e3fa869e4
commit 5bda59f94e
6 changed files with 41 additions and 27 deletions
+19 -7
View File
@@ -33,7 +33,7 @@ test('迁移归一化:生产旧命名 147–152 全部清理,152 未登记
])
})
test('迁移归一化:dev 顺延后的 152–158 一并清理(含已登记的 152)', () => {
test('迁移归一化:dev 旧命名 152–158 一并清理(含已登记的 152)', () => {
const stale = planLegacyConsignmentMigrationCleanup([
'001_init',
'146_voucher_consume_fallback_channel',
@@ -47,17 +47,29 @@ test('迁移归一化:dev 顺延后的 152–158 一并清理(含已登记
])
assert.deepEqual(stale, [
'152_consignment_platform',
'153_consignment_sms_logs',
'154_consignment_inventory_category_backfill',
'155_work_order_consignment_original_reward',
'156_work_order_internal_matching_deadline_guard',
'157_consignment_internal_match_cleanup',
'158_consignment_match_log_snapshot',
'152_consignment_platform',
])
})
test('迁移归一化:main 147–151 与 152 都已登记时不做任何清理', () => {
test('迁移归一化:main 147–152、158 已登记且无旧寄卖记录时不清理', () => {
const stale = planLegacyConsignmentMigrationCleanup([
'001_init',
'146_voucher_consume_fallback_channel',
...MAIN_MIGRATIONS,
'152_order_source_facts_immutable',
'158_consignment_worker_name_sync',
])
assert.deepEqual(stale, [])
})
test('迁移归一化:旧 152 已登记时清理记录,让 159 按新顺序重跑', () => {
const stale = planLegacyConsignmentMigrationCleanup([
'001_init',
'146_voucher_consume_fallback_channel',
@@ -65,7 +77,7 @@ test('迁移归一化:main 147–151 与 152 都已登记时不做任何清理
'152_consignment_platform',
])
assert.deepEqual(stale, [])
assert.deepEqual(stale, ['152_consignment_platform'])
})
test('迁移归一化:main 已执行、只剩旧寄卖记录时只清理旧名字', () => {
@@ -79,12 +91,12 @@ test('迁移归一化:main 已执行、只剩旧寄卖记录时只清理旧名
assert.deepEqual(stale, ['147_consignment_platform', '148_consignment_sms_logs'])
})
test('迁移归一化:152 已登记但 main 147–151 缺失时,152 也要重跑', () => {
test('迁移归一化:159 已登记但 main 147–151 缺失时,159 也要重跑', () => {
const stale = planLegacyConsignmentMigrationCleanup([
'001_init',
'146_voucher_consume_fallback_channel',
'152_consignment_platform',
'159_consignment_platform',
])
assert.deepEqual(stale, ['152_consignment_platform'])
assert.deepEqual(stale, ['159_consignment_platform'])
})
+8 -6
View File
@@ -25,8 +25,8 @@ const MIGRATIONS_TABLE = 'schema_migrations'
const SHORT_NUMERIC_PREFIX_MESSAGE = /^Can't determine timestamp for \d+$/
const MIGRATION_FILE_PATTERN = /^(\d{3})_.+\.sql$/i
/** 合并后的寄卖迁移文件名(不含 .sql);main 147–151 保持原编号。 */
const CONSOLIDATED_CONSIGNMENT_MIGRATION = '152_consignment_platform'
/** 合并后的寄卖迁移文件名(不含 .sql);main 的 147–152、158 保持原编号,寄卖合并文件顺延到 159。 */
const CONSOLIDATED_CONSIGNMENT_MIGRATION = '159_consignment_platform'
const MAIN_MIGRATIONS_BEFORE_CONSIGNMENT = [
'147_internal_sku_product_routing',
'148_fulfillment_execution_truth',
@@ -39,7 +39,8 @@ const MAIN_MIGRATIONS_BEFORE_CONSIGNMENT = [
* 历史上寄卖迁移用过两套编号,且都已被部分环境登记过:
* - 147_consignment_platform … 152_consignment_internal_match_cleanup(生产当前状态)
* - 152_consignment_platform … 158_consignment_match_log_snapshot(dev 顺延后、合并前)
* 合并后统一为 152_consignment_platform,这些旧名字必须从 schema_migrations 清掉。
* 合并 main 后 152/158 已被 main 的迁移占用,寄卖合并文件统一为 159_consignment_platform,
* 这些旧名字必须从 schema_migrations 清掉。
*/
const LEGACY_CONSIGNMENT_MIGRATION_NAMES = [
'147_consignment_platform',
@@ -48,6 +49,7 @@ const LEGACY_CONSIGNMENT_MIGRATION_NAMES = [
'150_work_order_consignment_original_reward',
'151_work_order_internal_matching_deadline_guard',
'152_consignment_internal_match_cleanup',
'152_consignment_platform',
'153_consignment_match_log_snapshot',
'153_consignment_sms_logs',
'154_consignment_inventory_category_backfill',
@@ -170,9 +172,9 @@ function assertMigrationFilesOrdered() {
* 计算需要从 schema_migrations 清理的旧寄卖迁移记录(纯函数,便于单测)。
*
* node-pg-migrate 的 checkOrder 是按位置逐项比对「已执行列表(ORDER BY run_on, id)」和
* 「本地迁移文件列表」,因此只改名/改 run_on 都不够:只要 152 已登记而 main 147–151 未登记,
* 152 就会占据第 147 个位置,和 147_internal_sku_product_routing 比对失败。
* 唯一稳妥的做法是删掉旧记录,让 147–152 按新文件顺序重新执行;152 内容幂等。
* 「本地迁移文件列表」,因此只改名/改 run_on 都不够:只要 159 已登记而 main 147–152 未登记,
* 159 就会占据错误位置,和 147_internal_sku_product_routing 比对失败。
* 唯一稳妥的做法是删掉旧记录,让 147–159 按新文件顺序重新执行;152/159 内容幂等。
*/
export function planLegacyConsignmentMigrationCleanup(appliedNames: readonly string[]): string[] {
const applied = new Set(appliedNames)
@@ -1,4 +1,4 @@
-- 152_consignment_platform.sql(原 147_consignment_platform;153–158 已合并入本文件,main 保留 147–151 后顺延)
-- 159_consignment_platform.sql(原 152_consignment_platform;main 的 147–152、158 保持原编号,本文件顺延)
-- 2026-11-09 合并:短信日志 / 分类回填 / 原始报酬 / 截止时间不变量 / 内部匹配清理 / 匹配日志快照。
-- 寄卖平台完整迁移(原 142–148 收敛为一个文件,2026-11-06)
-- 142 寄卖配置/库存/内部匹配
@@ -12,7 +12,7 @@ const ISSUE_REPO = new URL(
import.meta.url,
)
const FULFILLMENT = new URL('./consignment-fulfillment-service.ts', import.meta.url)
const MIGRATION = new URL('../../db/migrations/152_consignment_platform.sql', import.meta.url)
const MIGRATION = new URL('../../db/migrations/159_consignment_platform.sql', import.meta.url)
test('手动匹配不再在事务外改状态:数量不足/并发占库失败不能留下无截止时间的 internal_matching', async () => {
const source = await readFile(ENGINE, 'utf8')
@@ -149,9 +149,9 @@ test('降价提示:未售出时长支持一位小数,按小数小时判断',
assert.equal(suggestion?.suggestedPriceFen, 9_000)
})
test('合并迁移 152 必须包含寄卖配置、库存数量/售价与分配表', async () => {
test('合并迁移 159 必须包含寄卖配置、库存数量/售价与分配表', async () => {
const source = await readFile(
new URL('../../db/migrations/152_consignment_platform.sql', import.meta.url),
new URL('../../db/migrations/159_consignment_platform.sql', import.meta.url),
'utf8',
)
for (const fragment of [
@@ -163,7 +163,7 @@ test('合并迁移 152 必须包含寄卖配置、库存数量/售价与分配
'internal_match_deadline_at',
'consignment_inventory_id',
]) {
assert.ok(source.includes(fragment), `合并迁移 152 缺少 ${fragment}`)
assert.ok(source.includes(fragment), `合并迁移 159 缺少 ${fragment}`)
}
})
@@ -214,9 +214,9 @@ test('寄售数量上限按分类统计,并在打手配置接口返回 activeQ
assert.ok(source.includes('GROUP BY profile_id'), '各分类数量必须一次分组取回')
})
test('合并迁移 152 的苏尔南种子:降价提示默认开启、24 小时、按比例 10%', async () => {
test('合并迁移 159 的苏尔南种子:降价提示默认开启、24 小时、按比例 10%', async () => {
const sql = await readFile(
new URL('../../db/migrations/152_consignment_platform.sql', import.meta.url),
new URL('../../db/migrations/159_consignment_platform.sql', import.meta.url),
'utf8',
)
assert.match(
@@ -36,7 +36,7 @@ function option(label: string, value: string) {
return { label, value, enabled: true }
}
/** 苏尔南手枪种子配置的五个字段(与合并迁移 152 一致)。 */
/** 苏尔南手枪种子配置的五个字段(与合并迁移 159 一致)。 */
function surnanSpecs(): ConsignmentSpecField[] {
return [
{
@@ -522,9 +522,9 @@ test('动态规格:旧列仍由兼容 key 同步', () => {
})
})
test('合并迁移 152 必须包含动态规格的 JSON、匹配 key、文本与改价上限', async () => {
test('合并迁移 159 必须包含动态规格的 JSON、匹配 key、文本与改价上限', async () => {
const sql = await readFile(
new URL('../../db/migrations/152_consignment_platform.sql', import.meta.url),
new URL('../../db/migrations/159_consignment_platform.sql', import.meta.url),
'utf8',
)
for (const fragment of [
@@ -534,7 +534,7 @@ test('合并迁移 152 必须包含动态规格的 JSON、匹配 key、文本与
'price_cap_fen',
'CREATE INDEX IF NOT EXISTS idx_consignment_inventories_spec_key',
]) {
assert.ok(sql.includes(fragment), `合并迁移 152 缺少 ${fragment}`)
assert.ok(sql.includes(fragment), `合并迁移 159 缺少 ${fragment}`)
}
})
@@ -549,9 +549,9 @@ test('发布数量:关闭「允许修改寄售数量」时固定为 1,开启
assert.equal(resolveConsignmentPublishQuantity(true, 1.6), 2, '四舍五入')
})
test('合并迁移 152 必须为苏尔南手枪写入已发布的五个单选字段配置', async () => {
test('合并迁移 159 必须为苏尔南手枪写入已发布的五个单选字段配置', async () => {
const sql = await readFile(
new URL('../../db/migrations/152_consignment_platform.sql', import.meta.url),
new URL('../../db/migrations/159_consignment_platform.sql', import.meta.url),
'utf8',
)
for (const fragment of [
@@ -561,6 +561,6 @@ test('合并迁移 152 必须为苏尔南手枪写入已发布的五个单选字
"'published'",
'"key": "brillianceCount"',
]) {
assert.ok(sql.includes(fragment), `合并迁移 152 缺少 ${fragment}`)
assert.ok(sql.includes(fragment), `合并迁移 159 缺少 ${fragment}`)
}
})