This commit is contained in:
yml
2026-04-08 16:30:42 +08:00
commit 313c036845
131 changed files with 22393 additions and 0 deletions
@@ -0,0 +1,86 @@
import { getDb } from '../db/client.js'
export function createAdminAuditLog(input) {
const result = getDb().prepare(`
INSERT INTO admin_audit_logs (
actor_user_id,
actor_username,
actor_role,
action,
target_type,
target_id,
payload_json,
created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`).run(
input.actorUserId,
input.actorUsername,
input.actorRole,
input.action,
input.targetType,
input.targetId,
input.payloadJson,
input.createdAt,
)
return getAdminAuditLogById(Number(result.lastInsertRowid))
}
export function getAdminAuditLogById(logId) {
return getDb().prepare('SELECT * FROM admin_audit_logs WHERE id = ? LIMIT 1').get(logId) || null
}
export function listAdminAuditLogs(query = {}) {
const conditions = []
const values = []
if (query.actorUsername) {
conditions.push('actor_username = ?')
values.push(query.actorUsername)
}
if (query.action) {
conditions.push('action = ?')
values.push(query.action)
}
if (query.targetType) {
conditions.push('target_type = ?')
values.push(query.targetType)
}
if (query.dateFrom) {
conditions.push('created_at >= ?')
values.push(query.dateFrom)
}
if (query.dateTo) {
conditions.push('created_at <= ?')
values.push(query.dateTo)
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
const page = Number(query.page) || 1
const pageSize = Number(query.pageSize) || 20
const offset = (page - 1) * pageSize
const db = getDb()
const items = db.prepare(`
SELECT *
FROM admin_audit_logs
${whereClause}
ORDER BY id DESC
LIMIT ? OFFSET ?
`).all(...values, pageSize, offset)
const totalRow = db.prepare(`
SELECT COUNT(*) AS total
FROM admin_audit_logs
${whereClause}
`).get(...values)
return {
items,
total: Number(totalRow?.total || 0),
}
}
@@ -0,0 +1,117 @@
import { getDb } from '../db/client.js'
export function getAdminUserByUsername(username) {
return getDb().prepare('SELECT * FROM admin_users WHERE username = ? LIMIT 1').get(username) || null
}
export function getAdminUserById(userId) {
return getDb().prepare('SELECT * FROM admin_users WHERE id = ? LIMIT 1').get(userId) || null
}
export function createAdminUser(input) {
const result = getDb().prepare(`
INSERT INTO admin_users (
username,
password_hash,
role,
status,
created_at,
updated_at
) VALUES (?, ?, ?, ?, ?, ?)
`).run(
input.username,
input.passwordHash,
input.role,
input.status,
input.createdAt,
input.updatedAt,
)
return getAdminUserById(Number(result.lastInsertRowid))
}
export function listAdminUsers(query = {}) {
const conditions = []
const values = []
if (query.username) {
conditions.push('username LIKE ?')
values.push(`%${query.username}%`)
}
if (query.role) {
conditions.push('role = ?')
values.push(query.role)
}
if (query.status) {
conditions.push('status = ?')
values.push(query.status)
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
const page = Number(query.page) || 1
const pageSize = Number(query.pageSize) || 20
const offset = (page - 1) * pageSize
const db = getDb()
const items = db.prepare(`
SELECT *
FROM admin_users
${whereClause}
ORDER BY id DESC
LIMIT ? OFFSET ?
`).all(...values, pageSize, offset)
const totalRow = db.prepare(`
SELECT COUNT(*) AS total
FROM admin_users
${whereClause}
`).get(...values)
return {
items,
total: Number(totalRow?.total || 0),
}
}
export function updateAdminUser(userId, patch = {}) {
const current = getAdminUserById(userId)
if (!current) {
return null
}
const next = {
username: Object.prototype.hasOwnProperty.call(patch, 'username') ? patch.username : current.username,
password_hash: Object.prototype.hasOwnProperty.call(patch, 'password_hash') ? patch.password_hash : current.password_hash,
role: Object.prototype.hasOwnProperty.call(patch, 'role') ? patch.role : current.role,
status: Object.prototype.hasOwnProperty.call(patch, 'status') ? patch.status : current.status,
updated_at: Object.prototype.hasOwnProperty.call(patch, 'updated_at') ? patch.updated_at : current.updated_at,
}
getDb().prepare(`
UPDATE admin_users
SET username = ?, password_hash = ?, role = ?, status = ?, updated_at = ?
WHERE id = ?
`).run(
next.username,
next.password_hash,
next.role,
next.status,
next.updated_at,
userId,
)
return getAdminUserById(userId)
}
export function countActiveAdminUsers() {
const row = getDb().prepare(`
SELECT COUNT(*) AS total
FROM admin_users
WHERE role = 'admin' AND status = 'active'
`).get()
return Number(row?.total || 0)
}
+143
View File
@@ -0,0 +1,143 @@
import { getDb } from '../db/client.js'
export function findFirstAvailableCdkBySkuCode(skuCode) {
return getDb().prepare(`
SELECT *
FROM cdk_inventory
WHERE sku_code = ? AND status = 'available'
ORDER BY id ASC
LIMIT 1
`).get(skuCode) || null
}
export function assignReservedCdk(cdkId, taskId, updatedAt) {
getDb().prepare(`
UPDATE cdk_inventory
SET
status = 'reserved',
reserved_by_task_id = ?,
updated_at = ?
WHERE id = ? AND status = 'available'
`).run(taskId, updatedAt, cdkId)
return getCdkById(cdkId)
}
export function getCdkById(cdkId) {
return getDb().prepare('SELECT * FROM cdk_inventory WHERE id = ? LIMIT 1').get(cdkId) || null
}
export function markCdkDelivered(cdkId, deliveredAt) {
getDb().prepare(`
UPDATE cdk_inventory
SET
status = 'delivered',
delivered_at = ?,
updated_at = ?
WHERE id = ?
`).run(deliveredAt, deliveredAt, cdkId)
return getCdkById(cdkId)
}
export function listCdks({
page = 1,
pageSize = 20,
skuCode = '',
status = '',
batchNo = '',
} = {}) {
const offset = (page - 1) * pageSize
const filters = []
const params = []
if (skuCode) {
filters.push('sku_code = ?')
params.push(skuCode)
}
if (status) {
filters.push('status = ?')
params.push(status)
}
if (batchNo) {
filters.push('batch_no LIKE ?')
params.push(`%${batchNo}%`)
}
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
const db = getDb()
const totalRow = db.prepare(`
SELECT COUNT(*) AS total
FROM cdk_inventory
${whereClause}
`).get(...params)
const items = db.prepare(`
SELECT *
FROM cdk_inventory
${whereClause}
ORDER BY id DESC
LIMIT ? OFFSET ?
`).all(...params, pageSize, offset)
return {
items,
total: Number(totalRow?.total || 0),
}
}
export function createCdks(rows) {
const db = getDb()
const stmt = db.prepare(`
INSERT OR IGNORE INTO cdk_inventory (
batch_no,
sku_code,
cdk_code,
status,
reserved_by_task_id,
invalid_reason,
delivered_at,
created_at,
updated_at
) VALUES (?, ?, ?, 'available', NULL, '', NULL, ?, ?)
`)
let created = 0
for (const row of rows) {
const result = stmt.run(row.batchNo, row.skuCode, row.cdkCode, row.createdAt, row.updatedAt)
if (Number(result.changes || 0) > 0) {
created += 1
}
}
return created
}
export function releaseReservedCdk(cdkId, updatedAt) {
getDb().prepare(`
UPDATE cdk_inventory
SET
status = 'available',
reserved_by_task_id = NULL,
updated_at = ?
WHERE id = ? AND status = 'reserved'
`).run(updatedAt, cdkId)
return getCdkById(cdkId)
}
export function invalidateCdk(cdkId, invalidReason, updatedAt) {
getDb().prepare(`
UPDATE cdk_inventory
SET
status = 'invalid',
invalid_reason = ?,
updated_at = ?
WHERE id = ? AND status = 'available'
`).run(invalidReason, updatedAt, cdkId)
return getCdkById(cdkId)
}
@@ -0,0 +1,69 @@
import { getDb } from '../db/client.js'
export function createClaimToken(input) {
const result = getDb().prepare(`
INSERT INTO claim_tokens (
task_id,
token,
status,
expired_at,
used_at,
max_use_count,
used_count,
created_at,
updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
input.taskId,
input.token,
input.status,
input.expiredAt,
input.usedAt,
input.maxUseCount,
input.usedCount,
input.createdAt,
input.updatedAt,
)
return getClaimTokenById(Number(result.lastInsertRowid))
}
export function getClaimTokenById(tokenId) {
return getDb().prepare('SELECT * FROM claim_tokens WHERE id = ? LIMIT 1').get(tokenId) || null
}
export function findClaimTokenByToken(token) {
return getDb().prepare('SELECT * FROM claim_tokens WHERE token = ? LIMIT 1').get(token) || null
}
export function updateClaimToken(tokenId, patch) {
const current = getClaimTokenById(tokenId)
if (!current) {
return null
}
const next = { ...current, ...patch }
getDb().prepare(`
UPDATE claim_tokens
SET
status = ?,
expired_at = ?,
used_at = ?,
max_use_count = ?,
used_count = ?,
updated_at = ?
WHERE id = ?
`).run(
next.status,
next.expired_at,
next.used_at,
next.max_use_count,
next.used_count,
next.updated_at,
tokenId,
)
return getClaimTokenById(tokenId)
}
@@ -0,0 +1,99 @@
import { getDb } from '../db/client.js'
export function createMessageDelivery(input) {
const result = getDb().prepare(`
INSERT INTO message_deliveries (
platform,
channel,
order_id,
task_id,
platform_order_id,
recipient_key,
message_content,
claim_url,
status,
request_url,
request_headers_json,
request_body_json,
response_status,
response_json,
error_message,
sent_at,
created_at,
updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
input.platform,
input.channel,
input.orderId,
input.taskId,
input.platformOrderId,
input.recipientKey,
input.messageContent,
input.claimUrl,
input.status,
input.requestUrl,
input.requestHeadersJson,
input.requestBodyJson,
input.responseStatus,
input.responseJson,
input.errorMessage,
input.sentAt,
input.createdAt,
input.updatedAt,
)
return getMessageDeliveryById(Number(result.lastInsertRowid))
}
export function getMessageDeliveryById(deliveryId) {
return getDb().prepare('SELECT * FROM message_deliveries WHERE id = ? LIMIT 1').get(deliveryId) || null
}
export function updateMessageDelivery(deliveryId, patch = {}) {
const current = getMessageDeliveryById(deliveryId)
if (!current) {
return null
}
const next = { ...current, ...patch }
getDb().prepare(`
UPDATE message_deliveries
SET
status = ?,
request_url = ?,
request_headers_json = ?,
request_body_json = ?,
response_status = ?,
response_json = ?,
error_message = ?,
sent_at = ?,
updated_at = ?
WHERE id = ?
`).run(
next.status,
next.request_url,
next.request_headers_json,
next.request_body_json,
next.response_status,
next.response_json,
next.error_message,
next.sent_at,
next.updated_at,
deliveryId,
)
return getMessageDeliveryById(deliveryId)
}
export function findLatestSuccessfulMessageDeliveryByTask(taskId, channel) {
return getDb().prepare(`
SELECT *
FROM message_deliveries
WHERE task_id = ? AND channel = ? AND status = 'success'
ORDER BY id DESC
LIMIT 1
`).get(taskId, channel) || null
}
@@ -0,0 +1,80 @@
import { getDb } from '../db/client.js'
export function listOrderItemsByOrderId(orderId) {
return getDb().prepare(`
SELECT *
FROM order_items
WHERE order_id = ?
ORDER BY id ASC
`).all(orderId)
}
export function replaceOrderItems(orderId, items) {
const db = getDb()
const existingItems = listOrderItemsByOrderId(orderId)
const updateStatement = db.prepare(`
UPDATE order_items
SET
sku_code = ?,
sku_name = ?,
quantity = ?,
spec_json = ?,
delivery_mode = ?,
updated_at = ?
WHERE id = ?
`)
const insertStatement = db.prepare(`
INSERT INTO order_items (
order_id,
sku_code,
sku_name,
quantity,
spec_json,
delivery_mode,
created_at,
updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`)
for (let index = 0; index < items.length; index += 1) {
const item = items[index]
const existingItem = existingItems[index] || null
if (existingItem) {
updateStatement.run(
item.skuCode,
item.skuName,
item.quantity,
item.specJson,
item.deliveryMode,
item.updatedAt,
existingItem.id,
)
continue
}
insertStatement.run(
orderId,
item.skuCode,
item.skuName,
item.quantity,
item.specJson,
item.deliveryMode,
item.createdAt,
item.updatedAt,
)
}
if (existingItems.length > items.length) {
const redundantIds = existingItems.slice(items.length).map((item) => item.id)
const placeholders = redundantIds.map(() => '?').join(', ')
db.prepare(`DELETE FROM order_items WHERE order_id = ? AND id IN (${placeholders})`).run(orderId, ...redundantIds)
}
return listOrderItemsByOrderId(orderId)
}
export function getOrderItemById(orderItemId) {
return getDb().prepare('SELECT * FROM order_items WHERE id = ? LIMIT 1').get(orderItemId) || null
}
+144
View File
@@ -0,0 +1,144 @@
import { getDb } from '../db/client.js'
export function findOrderByPlatformOrderId(platform, platformOrderId) {
return getDb().prepare(`
SELECT *
FROM orders
WHERE platform = ? AND platform_order_id = ?
LIMIT 1
`).get(platform, platformOrderId) || null
}
export function createOrder(input) {
const result = getDb().prepare(`
INSERT INTO orders (
platform,
platform_order_id,
order_status,
pay_status,
buyer_id,
buyer_name,
receiver_contact,
total_amount,
currency,
raw_payload_json,
paid_at,
created_at,
updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
input.platform,
input.platformOrderId,
input.orderStatus,
input.payStatus,
input.buyerId,
input.buyerName,
input.receiverContact,
input.totalAmount,
input.currency,
input.rawPayloadJson,
input.paidAt,
input.createdAt,
input.updatedAt,
)
return getOrderById(Number(result.lastInsertRowid))
}
export function updateOrder(orderId, input) {
getDb().prepare(`
UPDATE orders
SET
order_status = ?,
pay_status = ?,
buyer_id = ?,
buyer_name = ?,
receiver_contact = ?,
total_amount = ?,
currency = ?,
raw_payload_json = ?,
paid_at = ?,
updated_at = ?
WHERE id = ?
`).run(
input.orderStatus,
input.payStatus,
input.buyerId,
input.buyerName,
input.receiverContact,
input.totalAmount,
input.currency,
input.rawPayloadJson,
input.paidAt,
input.updatedAt,
orderId,
)
return getOrderById(orderId)
}
export function getOrderById(orderId) {
return getDb().prepare('SELECT * FROM orders WHERE id = ? LIMIT 1').get(orderId) || null
}
export function listOrders({
page = 1,
pageSize = 20,
platformOrderId = '',
payStatus = '',
skuCode = '',
dateFrom = '',
dateTo = '',
} = {}) {
const offset = (page - 1) * pageSize
const filters = []
const params = []
if (platformOrderId) {
filters.push('o.platform_order_id LIKE ?')
params.push(`%${platformOrderId}%`)
}
if (payStatus) {
filters.push('o.pay_status = ?')
params.push(payStatus)
}
if (skuCode) {
filters.push('EXISTS (SELECT 1 FROM order_items oi WHERE oi.order_id = o.id AND oi.sku_code = ?)')
params.push(skuCode)
}
if (dateFrom) {
filters.push('o.created_at >= ?')
params.push(dateFrom)
}
if (dateTo) {
filters.push('o.created_at <= ?')
params.push(dateTo)
}
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
const db = getDb()
const totalRow = db.prepare(`
SELECT COUNT(*) AS total
FROM orders o
${whereClause}
`).get(...params)
const items = db.prepare(`
SELECT
o.*,
(SELECT COUNT(*) FROM delivery_tasks dt WHERE dt.order_id = o.id) AS task_count
FROM orders o
${whereClause}
ORDER BY o.id DESC
LIMIT ? OFFSET ?
`).all(...params, pageSize, offset)
return {
items,
total: Number(totalRow?.total || 0),
}
}
+228
View File
@@ -0,0 +1,228 @@
import { getDb } from '../db/client.js'
export function listTasksByOrderId(orderId) {
return getDb().prepare(`
SELECT *
FROM delivery_tasks
WHERE order_id = ?
ORDER BY id ASC
`).all(orderId)
}
export function createTask(input) {
const result = getDb().prepare(`
INSERT INTO delivery_tasks (
order_id,
order_item_id,
platform_order_id,
task_no,
task_status,
login_type,
claim_token_id,
reserved_cdk_id,
browser_session_id,
nickname,
role_id,
role_name,
area,
partition_name,
result_code,
result_message,
screenshot_path,
artifacts_json,
last_error,
retry_count,
expires_at,
claimed_at,
role_confirmed_at,
redeemed_at,
created_at,
updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
input.orderId,
input.orderItemId,
input.platformOrderId,
input.taskNo,
input.taskStatus,
input.loginType,
input.claimTokenId,
input.reservedCdkId,
input.browserSessionId,
input.nickname,
input.roleId,
input.roleName,
input.area,
input.partitionName,
input.resultCode,
input.resultMessage,
input.screenshotPath,
input.artifactsJson,
input.lastError,
input.retryCount,
input.expiresAt,
input.claimedAt,
input.roleConfirmedAt,
input.redeemedAt,
input.createdAt,
input.updatedAt,
)
return getTaskById(Number(result.lastInsertRowid))
}
export function updateTask(taskId, patch) {
const current = getTaskById(taskId)
if (!current) {
return null
}
const next = { ...current, ...patch }
getDb().prepare(`
UPDATE delivery_tasks
SET
task_status = ?,
login_type = ?,
claim_token_id = ?,
reserved_cdk_id = ?,
browser_session_id = ?,
nickname = ?,
role_id = ?,
role_name = ?,
area = ?,
partition_name = ?,
result_code = ?,
result_message = ?,
screenshot_path = ?,
artifacts_json = ?,
last_error = ?,
retry_count = ?,
expires_at = ?,
claimed_at = ?,
role_confirmed_at = ?,
redeemed_at = ?,
updated_at = ?
WHERE id = ?
`).run(
next.task_status,
next.login_type,
next.claim_token_id,
next.reserved_cdk_id,
next.browser_session_id,
next.nickname,
next.role_id,
next.role_name,
next.area,
next.partition_name,
next.result_code,
next.result_message,
next.screenshot_path,
next.artifacts_json,
next.last_error,
next.retry_count,
next.expires_at,
next.claimed_at,
next.role_confirmed_at,
next.redeemed_at,
next.updated_at,
taskId,
)
return getTaskById(taskId)
}
export function getTaskById(taskId) {
return getDb().prepare('SELECT * FROM delivery_tasks WHERE id = ? LIMIT 1').get(taskId) || null
}
export function findTaskByClaimTokenId(claimTokenId) {
return getDb().prepare(`
SELECT *
FROM delivery_tasks
WHERE claim_token_id = ?
LIMIT 1
`).get(claimTokenId) || null
}
export function listTasks({
page = 1,
pageSize = 20,
status = '',
platformOrderId = '',
taskNo = '',
skuCode = '',
roleId = '',
dateFrom = '',
dateTo = '',
} = {}) {
const offset = (page - 1) * pageSize
const filters = []
const params = []
if (status) {
filters.push('dt.task_status = ?')
params.push(status)
}
if (platformOrderId) {
filters.push('dt.platform_order_id LIKE ?')
params.push(`%${platformOrderId}%`)
}
if (taskNo) {
filters.push('dt.task_no LIKE ?')
params.push(`%${taskNo}%`)
}
if (skuCode) {
filters.push('oi.sku_code = ?')
params.push(skuCode)
}
if (roleId) {
filters.push('dt.role_id LIKE ?')
params.push(`%${roleId}%`)
}
if (dateFrom) {
filters.push('dt.created_at >= ?')
params.push(dateFrom)
}
if (dateTo) {
filters.push('dt.created_at <= ?')
params.push(dateTo)
}
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
const db = getDb()
const totalRow = db.prepare(`
SELECT COUNT(*) AS total
FROM delivery_tasks dt
LEFT JOIN order_items oi ON oi.id = dt.order_item_id
${whereClause}
`).get(...params)
const items = db.prepare(`
SELECT
dt.*,
oi.sku_code,
oi.sku_name,
ci.cdk_code,
ct.token AS claim_token
FROM delivery_tasks dt
LEFT JOIN order_items oi ON oi.id = dt.order_item_id
LEFT JOIN cdk_inventory ci ON ci.id = dt.reserved_cdk_id
LEFT JOIN claim_tokens ct ON ct.id = dt.claim_token_id
${whereClause}
ORDER BY dt.id DESC
LIMIT ? OFFSET ?
`).all(...params, pageSize, offset)
return {
items,
total: Number(totalRow?.total || 0),
}
}
@@ -0,0 +1,127 @@
import { getDb } from '../db/client.js'
export function createWebhookEvent(input) {
const result = getDb().prepare(`
INSERT INTO webhook_events (
platform,
event_type,
event_key,
signature_valid,
headers_json,
query_json,
body_json,
processed,
process_error,
related_order_id,
created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
input.platform,
input.eventType,
input.eventKey,
input.signatureValid ? 1 : 0,
input.headersJson,
input.queryJson,
input.bodyJson,
input.processed ? 1 : 0,
input.processError,
input.relatedOrderId,
input.createdAt,
)
return getWebhookEventById(Number(result.lastInsertRowid))
}
export function updateWebhookEvent(eventId, patch) {
const current = getWebhookEventById(eventId)
if (!current) {
return null
}
const next = { ...current, ...patch }
getDb().prepare(`
UPDATE webhook_events
SET
processed = ?,
process_error = ?,
related_order_id = ?
WHERE id = ?
`).run(next.processed ? 1 : 0, next.process_error, next.related_order_id, eventId)
return getWebhookEventById(eventId)
}
export function getWebhookEventById(eventId) {
return getDb().prepare('SELECT * FROM webhook_events WHERE id = ? LIMIT 1').get(eventId) || null
}
export function listWebhookEvents({
page = 1,
pageSize = 20,
platform = '',
processed = '',
relatedOrderId = '',
dateFrom = '',
dateTo = '',
} = {}) {
const offset = (page - 1) * pageSize
const filters = []
const params = []
if (platform) {
filters.push('platform = ?')
params.push(platform)
}
if (processed === '0' || processed === '1') {
filters.push('processed = ?')
params.push(Number(processed))
}
if (relatedOrderId) {
filters.push('related_order_id = ?')
params.push(Number(relatedOrderId))
}
if (dateFrom) {
filters.push('created_at >= ?')
params.push(dateFrom)
}
if (dateTo) {
filters.push('created_at <= ?')
params.push(dateTo)
}
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
const db = getDb()
const totalRow = db.prepare(`
SELECT COUNT(*) AS total
FROM webhook_events
${whereClause}
`).get(...params)
const items = db.prepare(`
SELECT *
FROM webhook_events
${whereClause}
ORDER BY id DESC
LIMIT ? OFFSET ?
`).all(...params, pageSize, offset)
return {
items,
total: Number(totalRow?.total || 0),
}
}
export function listWebhookEventsByOrderId(orderId) {
return getDb().prepare(`
SELECT *
FROM webhook_events
WHERE related_order_id = ?
ORDER BY id DESC
`).all(orderId)
}