Skip to content

Commit 65bf359

Browse files
hh
1 parent 4895bee commit 65bf359

5 files changed

Lines changed: 282 additions & 158 deletions

File tree

Lines changed: 58 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,78 @@
1-
import { MongoClient } from "mongodb";
1+
import clientPromise from "@/utils/mongo";
2+
import {
3+
buildHistoryFilter,
4+
fetchPriceHistory,
5+
mergeLegacyHistory,
6+
recordPriceHistoryEntry,
7+
} from "@/utils/priceHistoryStore";
28

39
export default async function handler( req, res ) {
410
const { cardId, set, number, rarity, edition } = req.query;
5-
611
if ( !cardId || !set || !number || !rarity || !edition ) {
7-
return res.status( 400 ).json( { error: "Missing parameters: cardId, set, number, rarity, edition" } );
12+
return res
13+
.status( 400 )
14+
.json( { error: "Missing parameters: cardId, set, number, rarity, edition" } );
815
}
916

1017
try {
11-
const client = new MongoClient( process.env.MONGODB_URI );
12-
await client.connect();
13-
const db = client.db( "cardPriceApp" );
14-
15-
// Fetch user-specific price history from "myCollection"
16-
const userDoc = await db.collection( "myCollection" ).findOne(
17-
{ setName: { $eq: set }, number: { $eq: number }, rarity: { $eq: rarity }, printing: { $eq: edition } },
18-
{ projection: { priceHistory: 1, _id: 0 } }
19-
);
20-
21-
// Fetch global price history from "priceHistory"
22-
const globalDoc = await db.collection( "priceHistory" ).findOne(
23-
{ cardId: { $eq: cardId }, setName: { $eq: set }, number: { $eq: number }, rarity: { $eq: rarity }, edition: { $eq: edition } },
24-
{ projection: { history: 1, _id: 0 } }
25-
);
26-
27-
// Extract history arrays
28-
const userHistory = userDoc?.priceHistory || [];
29-
const globalHistory = globalDoc?.history || [];
30-
31-
// Combine and sort history
32-
let combinedHistory = [ ...userHistory, ...globalHistory ]
33-
.map( entry => ( {
34-
date: new Date( entry.date ).toISOString().split( "T" )[ 0 ], // Standardize format
35-
price: parseFloat( entry.price )
36-
} ) )
37-
.sort( ( a, b ) => new Date( a.date ) - new Date( b.date ) );
38-
39-
// ✅ If no history exists, fetch price from YGOPRODeck API
40-
if ( combinedHistory.length === 0 ) {
41-
console.log( `🔍 No price history found for ${ cardId }. Fetching initial price...` );
18+
const db = ( await clientPromise ).db( "cardPriceApp" );
19+
const filter = buildHistoryFilter( {
20+
cardId,
21+
setName: set,
22+
number,
23+
rarity,
24+
edition,
25+
} );
26+
27+
// Prefer dedicated collection
28+
let history = await fetchPriceHistory( filter );
29+
30+
// One-time merge from legacy inline history if present
31+
if ( !history.length ) {
32+
const legacy = await db.collection( "myCollection" ).findOne(
33+
{ setName: set, number, rarity, printing: edition },
34+
{ projection: { priceHistory: 1, _id: 0 } }
35+
);
36+
if ( legacy?.priceHistory?.length ) {
37+
await mergeLegacyHistory( { filter, entries: legacy.priceHistory } );
38+
history = await fetchPriceHistory( filter );
39+
}
40+
}
4241

43-
const url = `https://db.ygoprodeck.com/api/v7/cardinfo.php?id=${ encodeURIComponent( cardId ) }&tcgplayer_data=true`;
42+
// Bootstrap with external price if still empty
43+
if ( !history.length ) {
44+
const url = `https://db.ygoprodeck.com/api/v7/cardinfo.php?id=${ encodeURIComponent(
45+
cardId
46+
) }&tcgplayer_data=true`;
4447
const response = await fetch( url );
4548
const data = await response.json();
4649

47-
if ( !data?.data || data?.data.length === 0 ) {
48-
await client.close();
49-
return res.status( 404 ).json( { error: "Card not found in external API" } );
50-
}
51-
52-
const card = data.data[ 0 ];
50+
const card = data?.data?.[ 0 ];
5351
const matchingSet = card?.card_sets?.find(
54-
( s ) => s.set_name === set && s.set_code === number && s.set_rarity === rarity && s.set_edition === edition
52+
( s ) =>
53+
s.set_name === set &&
54+
s.set_code === number &&
55+
s.set_rarity === rarity &&
56+
s.set_edition === edition
5557
);
5658

57-
if ( !matchingSet || !matchingSet.set_price ) {
58-
await client.close();
59-
return res.status( 404 ).json( { error: "Set price not available" } );
60-
}
61-
62-
const initialPrice = parseFloat( matchingSet.set_price );
63-
64-
if ( isNaN( initialPrice ) ) {
65-
console.error( "❌ Invalid price detected." );
66-
await client.close();
67-
return res.status( 500 ).json( { error: "Invalid price data" } );
68-
}
69-
70-
// ✅ Create initial price history entry
71-
const newEntry = { date: new Date().toISOString(), price: initialPrice };
72-
73-
await db.collection( "priceHistory" ).insertOne( {
74-
cardId,
75-
setName: set,
76-
number,
77-
rarity,
78-
edition,
79-
history: [ newEntry ]
80-
} );
81-
82-
combinedHistory = [ newEntry ]; // Update history for response
83-
} else {
84-
// ✅ Fetch the latest price if the last recorded date is not today
85-
const lastEntry = combinedHistory[ combinedHistory.length - 1 ];
86-
const lastEntryDate = new Date( lastEntry.date ).toISOString().split( "T" )[ 0 ];
87-
const todayDate = new Date().toISOString().split( "T" )[ 0 ];
88-
89-
if ( lastEntryDate !== todayDate ) {
90-
console.log( `🔍 Fetching latest price for ${ cardId }...` );
91-
92-
const url = `https://db.ygoprodeck.com/api/v7/cardinfo.php?id=${ encodeURIComponent( cardId ) }&tcgplayer_data=true`;
93-
const response = await fetch( url );
94-
const data = await response.json();
95-
96-
if ( data?.data?.length > 0 ) {
97-
const card = data.data[ 0 ];
98-
const matchingSet = card?.card_sets?.find(
99-
( s ) => s.set_name === set && s.set_code === number && s.set_rarity === rarity && s.set_edition === edition
100-
);
101-
102-
if ( matchingSet?.set_price ) {
103-
const latestPrice = parseFloat( matchingSet.set_price );
104-
105-
if ( !isNaN( latestPrice ) ) {
106-
console.log( `✅ Adding new price entry for ${ todayDate }: $${ latestPrice }` );
107-
108-
await db.collection( "priceHistory" ).updateOne(
109-
{ cardId: { $eq: cardId }, setName: { $eq: set }, number: { $eq: number }, rarity: { $eq: rarity }, edition: { $eq: edition } },
110-
{ $push: { history: { date: new Date().toISOString(), price: latestPrice } } },
111-
{ upsert: true }
112-
);
113-
114-
combinedHistory.push( { date: todayDate, price: latestPrice } );
115-
}
116-
}
117-
}
59+
const initialPrice = matchingSet?.set_price ? parseFloat( matchingSet.set_price ) : null;
60+
if ( Number.isFinite( initialPrice ) ) {
61+
await recordPriceHistoryEntry( {
62+
cardId,
63+
setName: set,
64+
number,
65+
rarity,
66+
edition,
67+
price: initialPrice,
68+
} );
69+
history = await fetchPriceHistory( filter );
11870
}
11971
}
12072

121-
await client.close();
122-
res.status( 200 ).json( { priceHistory: combinedHistory } );
73+
return res.status( 200 ).json( { priceHistory: history } );
12374
} catch ( error ) {
124-
console.error( "❌ Database Error:", error );
125-
res.status( 500 ).json( { error: "Internal Server Error" } );
75+
console.error( "price-history error:", error );
76+
return res.status( 500 ).json( { error: "Internal Server Error" } );
12677
}
12778
}
Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,29 @@
1-
// pages\api\Yugioh\card\[cardId]\update-price.js
2-
3-
import { MongoClient } from "mongodb";
1+
import { recordPriceHistoryEntry, buildHistoryFilter } from "@/utils/priceHistoryStore";
42

53
export default async function handler( req, res ) {
64
if ( req.method !== "POST" ) {
75
return res.status( 405 ).json( { error: "Method Not Allowed" } );
86
}
97

108
const { cardId, setName, number, rarity, edition, newPrice } = req.body;
11-
12-
if ( !cardId || !setName || !number || !rarity || !edition || isNaN( newPrice ) ) {
9+
const numericPrice = Number( newPrice );
10+
if ( !cardId || !setName || !number || !rarity || !edition || !Number.isFinite( numericPrice ) ) {
1311
return res.status( 400 ).json( { error: "Missing or invalid parameters" } );
1412
}
1513

1614
try {
17-
const client = new MongoClient( process.env.MONGODB_URI );
18-
await client.connect();
19-
const db = client.db( "cardPriceApp" );
20-
21-
const priceHistoryCollection = db.collection( "priceHistory" );
22-
23-
const existingDoc = await priceHistoryCollection.findOne( {
24-
cardId: { $eq: cardId }, setName: { $eq: setName }, number: { $eq: number }, rarity: { $eq: rarity }, edition: { $eq: edition }
15+
await recordPriceHistoryEntry( {
16+
cardId,
17+
setName,
18+
number,
19+
rarity,
20+
edition,
21+
price: numericPrice,
2522
} );
2623

27-
if ( !existingDoc ) {
28-
const newDoc = {
29-
cardId,
30-
setName,
31-
number,
32-
rarity,
33-
edition,
34-
history: [ { date: new Date().toISOString(), price: parseFloat( newPrice ) } ],
35-
};
36-
await priceHistoryCollection.insertOne( newDoc );
37-
} else {
38-
await priceHistoryCollection.updateOne(
39-
{ cardId: { $eq: cardId }, setName: { $eq: setName }, number: { $eq: number }, rarity: { $eq: rarity }, edition: { $eq: edition } },
40-
{ $push: { history: { date: new Date().toISOString(), price: parseFloat( newPrice ) } } },
41-
{ $upsert: true },
42-
43-
);
44-
}
45-
46-
await client.close();
47-
res.status( 200 ).json( { message: "Price updated successfully" } );
24+
return res.status( 200 ).json( { message: "Price updated successfully" } );
4825
} catch ( error ) {
49-
console.error( "❌ Database Error:", error );
50-
res.status( 500 ).json( { error: "Internal Server Error" } );
26+
console.error( "update-price error:", error );
27+
return res.status( 500 ).json( { error: "Internal Server Error" } );
5128
}
5229
}

0 commit comments

Comments
 (0)