diff --git a/api/db/item-annotations-queries.ts b/api/db/item-annotations-queries.ts index c5695b3..1164f63 100644 --- a/api/db/item-annotations-queries.ts +++ b/api/db/item-annotations-queries.ts @@ -46,7 +46,7 @@ export async function getAllItemAnnotationsForUser( ItemAnnotationRow & { platform_membership_id: string; destiny_version: DestinyVersion } >({ name: 'get_all_item_annotations', - text: 'SELECT platform_membership_id, destiny_version, inventory_item_id, tag, notes, variant, crafted_date FROM item_annotations WHERE membership_id = $1', + text: 'SELECT platform_membership_id, destiny_version, inventory_item_id, tag, notes, variant, crafted_date FROM item_annotations WHERE inventory_item_id != 0 and membership_id = $1', values: [bungieMembershipId], }); return results.rows.map((row) => ({ diff --git a/api/db/migration-state-queries.ts b/api/db/migration-state-queries.ts index 0a5c33d..377dac7 100644 --- a/api/db/migration-state-queries.ts +++ b/api/db/migration-state-queries.ts @@ -30,7 +30,7 @@ interface MigrationStateRow { export async function getUsersToMigrate(client: ClientBase): Promise { const results = await client.query({ name: 'get_users_to_migrate', - text: 'select distinct(s.membership_id) as membership_id from loadouts as s left join migration_state as m on s.membership_id = m.membership_id where m.membership_id is null limit 1000', + text: 'select membership_id from migration_state where state != 3 limit 1000', }); return results.rows.map((row) => row.membership_id); } @@ -214,7 +214,7 @@ export async function doMigration( }); metrics.increment('migration.finish.count'); } catch (e) { - console.error('Stately migration failed', e); + console.error(`Stately migration failed for ${bungieMembershipId}`, e); await transaction(async (client) => { await abortMigrationToStately( client, diff --git a/api/routes/import.ts b/api/routes/import.ts index e3a40ed..8c903a6 100644 --- a/api/routes/import.ts +++ b/api/routes/import.ts @@ -1,3 +1,4 @@ +import { StatelyError } from '@stately-cloud/client'; import { isEmpty } from 'es-toolkit/compat'; import asyncHandler from 'express-async-handler'; import { readTransaction } from '../db/index.js'; @@ -17,7 +18,6 @@ import { importHashTags } from '../stately/item-hash-tags-queries.js'; import { importLoadouts } from '../stately/loadouts-queries.js'; import { importSearches } from '../stately/searches-queries.js'; import { convertToStatelyItem } from '../stately/settings-queries.js'; -import { batches } from '../stately/stately-utils.js'; import { importTriumphs } from '../stately/triumphs-queries.js'; import { badRequest, delay, subtractObject } from '../utils.js'; @@ -151,7 +151,6 @@ export async function statelyImport( // Put the settings in first since it's in a different group await client.put({ item: settingsItem, - mustNotExist: true, }); // OK now put them in as fast as we can for (const batch of batches(items)) { diff --git a/api/stately/loadouts-queries.ts b/api/stately/loadouts-queries.ts index 2cbc1a0..20f888d 100644 --- a/api/stately/loadouts-queries.ts +++ b/api/stately/loadouts-queries.ts @@ -264,10 +264,10 @@ export function convertLoadoutCommonFieldsToStately( MessageInitShape | MessageInitShape, 'id' | '$typeName' > { - return { + const out = { destinyVersion, profileId: BigInt(platformMembershipId), - name: loadout.name, + name: loadout.name || 'Unnamed', classType: loadout.classType as number, equipped: (loadout.equipped || []).map(convertLoadoutItemToStately), unequipped: (loadout.unequipped || []).map(convertLoadoutItemToStately), @@ -276,6 +276,10 @@ export function convertLoadoutCommonFieldsToStately( createdAt: BigInt(loadout.createdAt ? new Date(loadout.createdAt).getTime() : 0n), lastUpdatedAt: BigInt(loadout.lastUpdatedAt ? new Date(loadout.lastUpdatedAt).getTime() : 0n), }; + if (out.lastUpdatedAt < out.createdAt) { + out.lastUpdatedAt = out.createdAt; + } + return out; } function convertLoadoutItemToStately(item: LoadoutItem): StatelyLoadoutItem { @@ -316,7 +320,7 @@ export function convertLoadoutParametersToStately( modsByBucket: modsByBucket ? Object.entries(modsByBucket).map(([bucketHash, modHashes]) => ({ bucketHash: Number(bucketHash), - modHashes, + modHashes: modHashes.filter((h) => Number.isInteger(h)), })) : undefined, }; @@ -328,8 +332,8 @@ export function statConstraintsToStately(statConstraints: StatConstraint[] | und return statConstraints && statConstraints.length > 0 ? statConstraints.map((c) => ({ statHash: c.statHash, - minTier: Math.max(0, c.minTier ?? 0), - maxTier: Math.min(c.maxTier ?? 10, 10), + minTier: Math.max(0, Math.floor(c.minTier ?? 0)), + maxTier: Math.min(Math.ceil(c.maxTier ?? 10), 10), })) : []; } diff --git a/api/stately/settings-queries.ts b/api/stately/settings-queries.ts index c4efb59..0b1a429 100644 --- a/api/stately/settings-queries.ts +++ b/api/stately/settings-queries.ts @@ -178,6 +178,8 @@ export function convertToStatelyItem( customStats, vaultWeaponGroupingStyle, itemPopupTab, + itemSize, + charCol, ...rest } = settings; @@ -227,6 +229,8 @@ export function convertToStatelyItem( wishListSources: wishListSource.split('|'), characterOrder: CharacterOrder[`CharacterOrder_${characterOrder}`], collapsedSections: collapsedSectionsList, + itemSize: Math.min(Math.max(0, itemSize), 66), + charCol: Math.min(Math.max(2, charCol), 5), infusionDirection: infusionDirection === InfuseDirection.FUEL ? StatelyInfuseDirection.InfuseDirection_Fuel