piclets / src /lib /db /piclets.ts
Fraser's picture
try profile
82f6d8e
import { db } from './index';
import type { PicletInstance } from './schema';
import { PicletType } from '../types/picletTypes';
import type { PicletStats } from '../types';
import { generatePicletId } from '../utils/picletId';
import type { UserInfo } from '../stores/auth';
// Interface for generated piclet data (from PicletResult component)
interface GeneratedPicletData {
name: string;
imageUrl: string;
imageData?: string;
imageCaption: string;
concept: string;
imagePrompt: string;
stats: PicletStats;
createdAt: Date;
}
/**
* Convert generated piclet data to a PicletInstance
* @param data - The generated piclet data with stats and images
* @param objectName - Optional normalized object name (e.g., "eiffel tower")
* @param attributes - Optional array of variation attributes (first item is the primary variation)
* @param visualDetails - Optional additional visual details
* @param userInfo - Optional HF user info for discoverer attribution
*/
export async function generatedDataToPicletInstance(
data: GeneratedPicletData,
objectName?: string,
attributes?: string[],
visualDetails?: string,
userInfo?: UserInfo | null
): Promise<Omit<PicletInstance, 'id'>> {
if (!data.stats) {
throw new Error('Generated data must have stats to create PicletInstance');
}
const stats = data.stats as PicletStats;
// Map tier from stats to discovery rarity
let tier: string = stats.tier || 'common';
// Generate typeId using normalized object name + variation (first attribute if any)
// Variation is "canonical" if there are no attributes or if first attribute is "canonical"
const normalizedObjectName = objectName || stats.name;
const variation = attributes && attributes.length > 0 ? attributes[0] : undefined;
const typeId = generatePicletId(normalizedObjectName, variation && variation !== 'canonical' ? variation : undefined);
return {
// Basic Info
typeId: typeId,
objectName: objectName || stats.name || data.name,
nickname: stats.name || data.name,
primaryType: stats.primaryType as PicletType,
tier: tier,
// Discovery Metadata
isCanonical: false, // Will be set by server
canonicalId: undefined,
variationAttributes: attributes || [],
// Populate discoverer info from auth if available
discoveredBy: userInfo?.preferred_username || 'Player', // Legacy field
discovererSub: userInfo?.sub,
discovererUsername: userInfo?.preferred_username,
discovererName: userInfo?.name,
discovererPicture: userInfo?.picture,
discoveredAt: new Date(),
scanCount: 1,
// Collection Management
isInCollection: true, // Auto-collected when scanned
collectedAt: new Date(),
// Visual Data
imageUrl: data.imageUrl,
imageData: data.imageData,
imageCaption: data.imageCaption,
visualDetails: visualDetails || '',
concept: data.concept,
description: stats.description,
imagePrompt: data.imagePrompt
};
}
// Save a piclet instance to the database
export async function savePicletInstance(picletInstance: Omit<PicletInstance, 'id'>): Promise<number> {
const id = await db.picletInstances.add(picletInstance as any);
return id;
}
// Update a piclet instance in the database
export async function updatePicletInstance(id: number, updates: Partial<PicletInstance>): Promise<void> {
await db.picletInstances.update(id, updates);
}
// Delete a piclet instance from the database
export async function deletePicletInstance(id: number): Promise<void> {
await db.picletInstances.delete(id);
}
// Get all piclet instances
export async function getAllPicletInstances(): Promise<PicletInstance[]> {
return await db.picletInstances.toArray();
}
// Get a single piclet instance by ID
export async function getPicletInstance(id: number): Promise<PicletInstance | undefined> {
return await db.picletInstances.get(id);
}
// Get collected piclets (those that have been discovered)
export async function getCollectedPiclets(): Promise<PicletInstance[]> {
const allRecords = await db.picletInstances.toArray();
return allRecords.filter(p => p.isInCollection === true);
}
// Get canonical piclets
export async function getCanonicalPiclets(): Promise<PicletInstance[]> {
// Use filter for boolean fields to avoid index issues
const allRecords = await db.picletInstances.toArray();
return allRecords.filter(p => p.isCanonical === true);
}
// Get piclets by object name
export async function getPicletsByObjectName(objectName: string): Promise<PicletInstance[]> {
return await db.picletInstances.where('objectName').equals(objectName).toArray();
}
// Get variations of a canonical piclet
export async function getVariations(canonicalId: string): Promise<PicletInstance[]> {
return await db.picletInstances.where('canonicalId').equals(canonicalId).toArray();
}
// Update scan count
export async function updateScanCount(picletId: number): Promise<void> {
const piclet = await db.picletInstances.get(picletId);
if (piclet) {
await db.picletInstances.update(picletId, {
scanCount: (piclet.scanCount || 0) + 1
});
}
}