2026-02-15 15:25:08 -05:00
|
|
|
import 'dotenv/config';
|
|
|
|
|
|
|
|
|
|
import chalk from 'chalk';
|
2026-03-11 19:18:45 -04:00
|
|
|
import { db, ClosePool } from '../src/db/index.ts';
|
2026-02-15 15:25:08 -05:00
|
|
|
import { sql, inArray, eq } from 'drizzle-orm';
|
2026-03-12 08:18:40 -04:00
|
|
|
import { skus, processingSkus, priceHistory } from '../src/db/schema.ts';
|
2026-03-11 19:18:45 -04:00
|
|
|
import { toSnakeCase } from 'drizzle-orm/casing';
|
2026-03-12 08:18:40 -04:00
|
|
|
import * as Indexing from './indexing.ts';
|
2026-02-15 15:25:08 -05:00
|
|
|
|
|
|
|
|
|
2026-03-05 07:11:54 -05:00
|
|
|
function sleep(ms: number) {
|
|
|
|
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-15 15:25:08 -05:00
|
|
|
async function resetProcessingTable() {
|
|
|
|
|
// Use sql.raw to execute the TRUNCATE TABLE statement
|
2026-03-11 19:18:45 -04:00
|
|
|
await db.execute(sql.raw('TRUNCATE TABLE pokemon.processing_skus;'));
|
2026-02-15 15:25:08 -05:00
|
|
|
await db.insert(processingSkus).select(db.select({skuId: skus.skuId}).from(skus));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function syncPrices() {
|
|
|
|
|
const batchSize = 1000;
|
2026-03-03 07:59:44 -05:00
|
|
|
// const skuIndex = client.collections('skus');
|
2026-02-15 15:25:08 -05:00
|
|
|
|
|
|
|
|
await resetProcessingTable();
|
|
|
|
|
console.log(chalk.green('Processing table reset and populated with current SKUs.'));
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
const batch = await db.select().from(processingSkus).limit(batchSize);
|
|
|
|
|
if (batch.length === 0) {
|
|
|
|
|
console.log('All SKUs processed.');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const skuIds = batch.map(item => item.skuId);
|
|
|
|
|
console.log(`${chalk.blue('Processing SKUs:')} ${chalk.gray(skuIds.join(', '))}`);
|
|
|
|
|
|
|
|
|
|
const skuResponse = await fetch('https://mpgateway.tcgplayer.com/v1/pricepoints/marketprice/skus/search', {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify({ skuIds: skuIds }),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!skuResponse.ok) {
|
|
|
|
|
console.error('Error fetching SKU pricing:', skuResponse.statusText);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const skuData = await skuResponse.json();
|
|
|
|
|
|
|
|
|
|
if (skuData.length !== batchSize) {
|
|
|
|
|
console.error(chalk.yellow(`Expected ${batchSize} SKUs, got ${skuData.length}`));
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-03 07:59:44 -05:00
|
|
|
const skuUpdates = skuData.map((sku: any) => { return {
|
|
|
|
|
skuId: sku.skuId,
|
|
|
|
|
cardId: 0,
|
|
|
|
|
productId: 0,
|
|
|
|
|
condition: '',
|
|
|
|
|
language: '',
|
|
|
|
|
variant: '',
|
|
|
|
|
calculatedAt: sku.calculatedAt ? new Date(sku.calculatedAt) : null,
|
|
|
|
|
highestPrice: sku.highestPrice,
|
|
|
|
|
lowestPrice: sku.lowestPrice,
|
|
|
|
|
marketPrice: sku.marketPrice,
|
|
|
|
|
priceCount: null,
|
|
|
|
|
}});
|
2026-03-12 08:18:40 -04:00
|
|
|
const skuRows = await db.insert(skus).values(skuUpdates).onConflictDoUpdate({
|
2026-03-11 19:18:45 -04:00
|
|
|
target: skus.skuId,
|
2026-03-03 07:59:44 -05:00
|
|
|
set: {
|
2026-03-11 19:18:45 -04:00
|
|
|
calculatedAt: sql.raw(`excluded.${toSnakeCase(skus.calculatedAt.name)}`),
|
|
|
|
|
highestPrice: sql.raw(`excluded.${toSnakeCase(skus.highestPrice.name)}`),
|
|
|
|
|
lowestPrice: sql.raw(`excluded.${toSnakeCase(skus.lowestPrice.name)}`),
|
|
|
|
|
marketPrice: sql.raw(`excluded.${toSnakeCase(skus.marketPrice.name)}`),
|
2026-03-03 07:59:44 -05:00
|
|
|
}
|
|
|
|
|
});
|
2026-02-15 15:25:08 -05:00
|
|
|
|
2026-03-03 07:59:44 -05:00
|
|
|
// remove skus from the 'working' processingSkus table
|
2026-02-15 15:25:08 -05:00
|
|
|
await db.delete(processingSkus).where(inArray(processingSkus.skuId, skuIds));
|
|
|
|
|
|
2026-03-05 07:11:54 -05:00
|
|
|
// be nice to the API and not send too many requests in a short time
|
2026-03-11 19:18:45 -04:00
|
|
|
await sleep(200);
|
2026-02-15 15:25:08 -05:00
|
|
|
}
|
|
|
|
|
|
2026-03-03 07:59:44 -05:00
|
|
|
}
|
|
|
|
|
|
2026-02-15 15:25:08 -05:00
|
|
|
|
|
|
|
|
const start = Date.now();
|
|
|
|
|
await syncPrices();
|
2026-03-12 08:18:40 -04:00
|
|
|
await Indexing.upsertSkuCollection(db);
|
2026-03-11 19:18:45 -04:00
|
|
|
await ClosePool();
|
2026-02-15 15:25:08 -05:00
|
|
|
const end = Date.now();
|
|
|
|
|
const duration = (end - start) / 1000;
|
|
|
|
|
console.log(chalk.green(`Price sync completed in ${duration.toFixed(2)} seconds.`));
|
|
|
|
|
|
|
|
|
|
export {};
|