import { v } from "convex/values"; import { query, mutation } from "./_generated/server"; // Get all cards (for local caching) export const list = query({ args: {}, handler: async (ctx) => { return await ctx.db.query("cards").collect(); }, }); // Get cards updated after a timestamp (for incremental sync) export const listUpdatedAfter = query({ args: { since: v.number() }, handler: async (ctx, { since }) => { return await ctx.db .query("cards") .withIndex("by_updated", (q) => q.gt("updatedAt", since)) .collect(); }, }); // Get a single card by Scryfall ID export const getByScryfallId = query({ args: { scryfallId: v.string() }, handler: async (ctx, { scryfallId }) => { return await ctx.db .query("cards") .withIndex("by_scryfall", (q) => q.eq("scryfallId", scryfallId)) .first(); }, }); // Get cards by oracle ID (all printings of a card) export const getByOracleId = query({ args: { oracleId: v.string() }, handler: async (ctx, { oracleId }) => { return await ctx.db .query("cards") .withIndex("by_oracle", (q) => q.eq("oracleId", oracleId)) .collect(); }, }); // Search cards by name export const searchByName = query({ args: { name: v.string() }, handler: async (ctx, { name }) => { const cards = await ctx.db.query("cards").collect(); const lowerName = name.toLowerCase(); return cards.filter((card) => card.name.toLowerCase().includes(lowerName) ); }, }); // Get total card count export const count = query({ args: {}, handler: async (ctx) => { const cards = await ctx.db.query("cards").collect(); return cards.length; }, }); // Insert a card (used by migration script) export const insert = mutation({ args: { scryfallId: v.string(), oracleId: v.string(), name: v.string(), setCode: v.string(), collectorNumber: v.string(), rarity: v.string(), artist: v.optional(v.string()), imageUri: v.optional(v.string()), hash: v.bytes(), hashVersion: v.number(), }, handler: async (ctx, args) => { // Check if card already exists const existing = await ctx.db .query("cards") .withIndex("by_scryfall", (q) => q.eq("scryfallId", args.scryfallId)) .first(); if (existing) { // Update existing card await ctx.db.patch(existing._id, { ...args, updatedAt: Date.now(), }); return existing._id; } // Insert new card return await ctx.db.insert("cards", { ...args, updatedAt: Date.now(), }); }, }); // Batch insert cards export const insertBatch = mutation({ args: { cards: v.array( v.object({ scryfallId: v.string(), oracleId: v.string(), name: v.string(), setCode: v.string(), collectorNumber: v.string(), rarity: v.string(), artist: v.optional(v.string()), imageUri: v.optional(v.string()), hash: v.bytes(), hashVersion: v.number(), }) ), }, handler: async (ctx, { cards }) => { const results = []; for (const card of cards) { const existing = await ctx.db .query("cards") .withIndex("by_scryfall", (q) => q.eq("scryfallId", card.scryfallId)) .first(); if (existing) { await ctx.db.patch(existing._id, { ...card, updatedAt: Date.now(), }); results.push(existing._id); } else { const id = await ctx.db.insert("cards", { ...card, updatedAt: Date.now(), }); results.push(id); } } return results; }, });