202610100007_owner_handles.js
1.94 KB
/**
* 主人的 id(handle):Agent 的全名是「名字@主人 id」,如 小火子@yibo。
* - 新表 vk_owner_handles(handle 全局唯一);给已有的人类用户按邮箱 @ 前的部分回填,重名的加数字后缀。
* - vk_agents 增加 UNIQUE(owner_user_id, name):同一主人名下 Agent 不重名,全名因此全局唯一。
*/
const HANDLES = 'vk_owner_handles'
export async function up(db) {
await db.schema.createTable(HANDLES, (t) => {
t.string('user_id', 64).primary()
t.string('handle', 32).notNullable()
t.datetime('created_at', { precision: 3 }).notNullable()
t.unique(['handle'], { indexName: 'uq_vk_owner_handles_handle' })
t.check("handle regexp '^[a-z0-9][a-z0-9_-]{1,31}$'", [], 'ck_vk_owner_handles_format')
})
const users = await db('users').where((q) => q.whereNull('role').orWhereNot({ role: 'agent' })).orderBy('created_at', 'asc').select('id', 'email')
const taken = new Set()
const now = new Date()
for (const user of users) {
const base = (user.email.split('@')[0].toLowerCase().replace(/[^a-z0-9_-]/g, '-').replace(/^[^a-z0-9]+/, '') || 'user').slice(0, 24).padEnd(2, '0')
let handle = base
for (let n = 2; taken.has(handle); n += 1) handle = `${base}-${n}`
taken.add(handle)
await db(HANDLES).insert({ user_id: user.id, handle, created_at: now })
}
const duplicate = await db('vk_agents').whereNotNull('owner_user_id').groupBy('owner_user_id', 'name').havingRaw('COUNT(*) > 1').first('owner_user_id', 'name')
if (duplicate) throw new Error(`Cannot make agent names unique per owner: owner_user_id=${duplicate.owner_user_id}, name=${duplicate.name}`)
await db.schema.alterTable('vk_agents', (t) => t.unique(['owner_user_id', 'name'], { indexName: 'uq_vk_agents_owner_name' }))
}
export async function down(db) {
await db.schema.alterTable('vk_agents', (t) => t.dropUnique(['owner_user_id', 'name'], 'uq_vk_agents_owner_name'))
await db.schema.dropTable(HANDLES)
}