111 lines
3.6 KiB
JavaScript
111 lines
3.6 KiB
JavaScript
import {
|
|
amazon_product,
|
|
amazon_search_item,
|
|
amazon_review
|
|
} from '../models/index.js';
|
|
import { safe_json_stringify } from './json_utils.js';
|
|
|
|
function build_batch_key(prefix) {
|
|
return `${prefix}_${Date.now()}_${Math.random().toString().slice(2, 8)}`;
|
|
}
|
|
|
|
function pick_asin_from_url(url) {
|
|
if (!url) return null;
|
|
const m = String(url).match(/\/dp\/([A-Z0-9]{8,16})/i);
|
|
return m && m[1] ? m[1].toUpperCase() : null;
|
|
}
|
|
|
|
export async function persist_amazon_result({ result }) {
|
|
if (!result || !result.stage) {
|
|
return;
|
|
}
|
|
|
|
if (result.stage === 'detail') {
|
|
const asin = result.asin || pick_asin_from_url(result.url);
|
|
if (!asin) {
|
|
return;
|
|
}
|
|
|
|
await amazon_product.upsert({
|
|
asin,
|
|
url: result.url || '',
|
|
title: result.title || null,
|
|
price: result.price || null,
|
|
sku: result.sku || null,
|
|
sku_color: result.sku_color || null,
|
|
sku_size: result.sku_size || null,
|
|
brand_line: result.brand_line || null,
|
|
brand_store_url: result.brand_store_url || null,
|
|
ac_badge: result.ac_badge || null,
|
|
bestseller_hint: result.bestseller_hint || null,
|
|
delivery_hint: result.delivery_hint || null,
|
|
social_proof: result.social_proof || null,
|
|
sustainability_hint: result.sustainability_hint || null,
|
|
rating_stars: result.rating_stars || null,
|
|
review_count_text: result.review_count_text || null,
|
|
main_image: result.main_image || null,
|
|
images_json: safe_json_stringify(result.images || []),
|
|
bullets_json: safe_json_stringify(result.bullets || []),
|
|
product_info_json: safe_json_stringify(result.product_info || {}),
|
|
detail_extra_lines_json: safe_json_stringify(result.detail_extra_lines || [])
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (result.stage === 'list') {
|
|
const batch_key = build_batch_key('list');
|
|
const items = Array.isArray(result.items) ? result.items : [];
|
|
|
|
for (const it of items) {
|
|
const asin = it.asin || pick_asin_from_url(it.url);
|
|
if (!asin || !it.url) continue;
|
|
|
|
await amazon_search_item.create({
|
|
asin,
|
|
url: it.url,
|
|
title: it.title || null,
|
|
price: it.price || null,
|
|
rating: typeof it.rating === 'number' ? it.rating : null,
|
|
rating_text: it.rating_text || null,
|
|
review_count: typeof it.review_count === 'number' ? it.review_count : null,
|
|
review_count_text: it.review_count_text || null,
|
|
rank_index: typeof it.index === 'number' ? it.index : null,
|
|
batch_key,
|
|
batch_total: typeof result.total === 'number' ? result.total : null,
|
|
batch_limit: typeof result.limit === 'number' ? result.limit : null
|
|
});
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (result.stage === 'reviews') {
|
|
const batch_key = build_batch_key('reviews');
|
|
const asin = pick_asin_from_url(result.url);
|
|
const items = Array.isArray(result.items) ? result.items : [];
|
|
|
|
for (const it of items) {
|
|
const review_id = it.review_id;
|
|
if (!review_id) continue;
|
|
|
|
const asin_value = asin || pick_asin_from_url(it.url) || pick_asin_from_url(result.url);
|
|
|
|
await amazon_review.upsert({
|
|
asin: asin_value || null,
|
|
url: result.url || '',
|
|
review_id,
|
|
author: it.author || null,
|
|
title: it.title || null,
|
|
body: it.body || null,
|
|
rating_text: it.rating_text || null,
|
|
review_date: it.date || null,
|
|
review_index: typeof it.index === 'number' ? it.index : null,
|
|
batch_key,
|
|
batch_total: typeof result.total === 'number' ? result.total : null,
|
|
batch_limit: typeof result.limit === 'number' ? result.limit : null
|
|
});
|
|
}
|
|
}
|
|
}
|