[feat] implemented product variants

This commit is contained in:
2026-02-23 19:05:55 -05:00
parent 30433696e5
commit 240e4ce88b
6 changed files with 52 additions and 15 deletions

View File

@@ -148,10 +148,10 @@ async function syncProductLine(productLine: string, field: string, fieldValue: s
const detailData = await detailResponse.json(); const detailData = await detailResponse.json();
await db.insert(schema.cards).values({ await db.insert(schema.tcgcards).values({
productId: item.productId, productId: item.productId,
originalProductName: item.productName, productName: item.productName,
productName: cleanProductName(item.productName), //productName: cleanProductName(item.productName),
rarityName: item.rarityName, rarityName: item.rarityName,
productLineName: item.productLineName, productLineName: item.productLineName,
productLineUrlName: item.productLineUrlName, productLineUrlName: item.productLineUrlName,
@@ -187,8 +187,8 @@ async function syncProductLine(productLine: string, field: string, fieldValue: s
Artist: detailData.formattedAttributes.Artist || null, Artist: detailData.formattedAttributes.Artist || null,
}).onDuplicateKeyUpdate({ }).onDuplicateKeyUpdate({
set: { set: {
originalProductName: item.productName, productName: item.productName,
productName: cleanProductName(item.productName), //productName: cleanProductName(item.productName),
rarityName: item.rarityName, rarityName: item.rarityName,
productLineName: item.productLineName, productLineName: item.productLineName,
productLineUrlName: item.productLineUrlName, productLineUrlName: item.productLineUrlName,

View File

@@ -23,6 +23,7 @@ async function createCollection(client: Client) {
name: 'cards', name: 'cards',
fields: [ fields: [
{ name: 'productId', type: 'int32' }, { name: 'productId', type: 'int32' },
{ name: 'variant', type: 'string' },
{ name: 'productName', type: 'string' }, { name: 'productName', type: 'string' },
{ name: 'productLineName', type: 'string', facet: true }, { name: 'productLineName', type: 'string', facet: true },
{ name: 'rarityName', type: 'string', facet: true }, { name: 'rarityName', type: 'string', facet: true },
@@ -33,7 +34,7 @@ async function createCollection(client: Client) {
{ name: 'Artist', type: 'string' }, { name: 'Artist', type: 'string' },
{ name: 'sealed', type: 'bool' }, { name: 'sealed', type: 'bool' },
], ],
default_sorting_field: 'productId', //default_sorting_field: 'productId',
}); });
console.log(chalk.green('Collection "cards" created successfully.')); console.log(chalk.green('Collection "cards" created successfully.'));
} else { } else {
@@ -54,6 +55,7 @@ async function preloadSearchIndex() {
await client.collections('cards').documents().import(pokemon.map(card => ({ await client.collections('cards').documents().import(pokemon.map(card => ({
productId: card.productId, productId: card.productId,
variant: card.variant,
productName: card.productName, productName: card.productName,
productLineName: card.productLineName, productLineName: card.productLineName,
rarityName: card.rarityName, rarityName: card.rarityName,

View File

@@ -4,8 +4,8 @@ import * as schema from "./schema.ts";
export const relations = defineRelations(schema, (r) => ({ export const relations = defineRelations(schema, (r) => ({
skus: { skus: {
card: r.one.cards({ card: r.one.cards({
from: r.skus.productId, from: [r.skus.productId, r.skus.variant],
to: r.cards.productId, to: [r.cards.productId, r.cards.variant],
}), }),
}, },
cards: { cards: {

View File

@@ -1,8 +1,7 @@
import { mysqlTable, int, varchar, boolean, decimal, datetime, index } from "drizzle-orm/mysql-core" import { mysqlTable, int, varchar, boolean, decimal, datetime, index } from "drizzle-orm/mysql-core"
export const cards = mysqlTable("cards", { export const tcgcards = mysqlTable("tcgcards", {
productId: int().primaryKey(), productId: int().primaryKey(),
originalProductName: varchar({ length: 255 }).default("").notNull(),
productName: varchar({ length: 255 }).notNull(), productName: varchar({ length: 255 }).notNull(),
productLineName: varchar({ length: 255 }).default("").notNull(), productLineName: varchar({ length: 255 }).default("").notNull(),
productLineUrlName: varchar({ length: 255 }).default("").notNull(), productLineUrlName: varchar({ length: 255 }).default("").notNull(),
@@ -41,6 +40,39 @@ export const cards = mysqlTable("cards", {
Artist: varchar({ length: 255 }), Artist: varchar({ length: 255 }),
}); });
export const cards = mysqlTable("cards", {
cardId: int().notNull().primaryKey().autoincrement(),
productId: int().notNull(),
variant: varchar({ length: 100 }).notNull(),
productName: varchar({ length: 255 }),
productLineName: varchar({ length: 255 }),
productUrlName: varchar({ length: 255 }).default("").notNull(),
rarityName: varchar({ length: 100 }),
sealed: boolean().default(false).notNull(),
setId: int(),
cardType: varchar({ length: 100 }),
energyType: varchar({ length: 100 }),
number: varchar({ length: 50 }),
Artist: varchar({ length: 255 }),
},
(table) => [
index("card_productIdIdx").on(table.productId, table.variant),
]);
export const tcg_overrides = mysqlTable("tcg_overrides", {
productId: int().primaryKey(),
productName: varchar({ length: 255 }),
productLineName: varchar({ length: 255 }),
productUrlName: varchar({ length: 255 }).default("").notNull(),
rarityName: varchar({ length: 100 }),
sealed: boolean().default(false).notNull(),
setId: int(),
cardType: varchar({ length: 100 }),
energyType: varchar({ length: 100 }),
number: varchar({ length: 50 }),
Artist: varchar({ length: 255 }),
});
export const sets = mysqlTable("sets", { export const sets = mysqlTable("sets", {
setId: int().primaryKey(), setId: int().primaryKey(),
setName: varchar({ length: 255 }).notNull(), setName: varchar({ length: 255 }).notNull(),
@@ -50,6 +82,7 @@ export const sets = mysqlTable("sets", {
export const skus = mysqlTable("skus", { export const skus = mysqlTable("skus", {
skuId: int().primaryKey(), skuId: int().primaryKey(),
cardId: int().default(0).notNull(),
productId: int().notNull(), productId: int().notNull(),
condition: varchar({ length: 255 }).notNull(), condition: varchar({ length: 255 }).notNull(),
language: varchar({ length: 100 }).notNull(), language: varchar({ length: 100 }).notNull(),
@@ -61,7 +94,7 @@ export const skus = mysqlTable("skus", {
priceCount: int(), priceCount: int(),
}, },
(table) => [ (table) => [
index("productIdIdx").on(table.productId), index("productIdIdx").on(table.productId, table.variant),
]); ]);
export const processingSkus = mysqlTable("processingSkus", { export const processingSkus = mysqlTable("processingSkus", {

View File

@@ -15,12 +15,12 @@ export const partial = true;
export const prerender = false; export const prerender = false;
const searchParams = Astro.url.searchParams; const searchParams = Astro.url.searchParams;
const productId = Number(searchParams.get('productId')) || 0; const cardId = Number(searchParams.get('cardId')) || 0;
// query the database for the card with the given productId and return the card data as json // query the database for the card with the given productId and return the card data as json
const card = await db.query.cards.findFirst({ const card = await db.query.cards.findFirst({
where: { productId: Number(productId) }, where: { cardId: Number(cardId) },
with: { with: {
prices: true, prices: true,
set: true, set: true,
@@ -29,7 +29,8 @@ const card = await db.query.cards.findFirst({
const nearMint = await db.query.skus.findFirst({ const nearMint = await db.query.skus.findFirst({
where: { where: {
productId: Number(productId), productId: card?.productId || 0,
variant: card?.variant || "",
} }
}); });

View File

@@ -52,7 +52,7 @@ const conditionOrder = ["Near Mint", "Lightly Played", "Moderately Played", "Hea
<div class="inventory-button position-relative float-end shadow-filter text-center d-none"> <div class="inventory-button position-relative float-end shadow-filter text-center d-none">
<div class="inventory-label pt-2">+/-</div> <div class="inventory-label pt-2">+/-</div>
</div> </div>
<div hx-get={`/partials/card-modal?productId=${card.productId}`} hx-target="#cardModal" hx-trigger="click" data-bs-toggle="modal" data-bs-target="#cardModal"> <div hx-get={`/partials/card-modal?cardId=${card.cardId}`} hx-target="#cardModal" hx-trigger="click" data-bs-toggle="modal" data-bs-target="#cardModal">
<img src={`/cards/${card.productId}.jpg`} alt={card.productName} loading="lazy" decoding="async" class="img-fluid rounded-3 mb-2 card-image w-100" onerror="this.onerror=null;this.src='/cards/noImage.webp'"/> <img src={`/cards/${card.productId}.jpg`} alt={card.productName} loading="lazy" decoding="async" class="img-fluid rounded-3 mb-2 card-image w-100" onerror="this.onerror=null;this.src='/cards/noImage.webp'"/>
</div> </div>
<div class="row row-cols-5 gx-1 price-row mb-2"> <div class="row row-cols-5 gx-1 price-row mb-2">
@@ -75,6 +75,7 @@ const conditionOrder = ["Near Mint", "Lightly Played", "Moderately Played", "Hea
<div class="text-secondary">{card.number}</div> <div class="text-secondary">{card.number}</div>
<span class="ps-2 small-icon"><RarityIcon rarity={card.rarityName} /></span> <span class="ps-2 small-icon"><RarityIcon rarity={card.rarityName} /></span>
</div> </div>
<div>{card.variant}</div>
</div> </div>
))} ))}
{start + 20 < totalHits && {start + 20 < totalHits &&