Skip to content

Commit

Permalink
Merge pull request #251 from DestinyItemManager/stately-update
Browse files Browse the repository at this point in the history
Update stately, use mustNotExist for loadout shares
  • Loading branch information
bhollis authored Dec 10, 2024
2 parents aaa26e4 + 1ef3e86 commit 396b6e3
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 101 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,4 @@ jobs:
run: pnpm test
env:
STATELY_STORE_ID: ${{ vars.STATELY_STORE_ID}}
STATELY_CLIENT_ID: ${{ vars.STATELY_CLIENT_ID }}
STATELY_CLIENT_SECRET: ${{ secrets.STATELY_CLIENT_SECRET }}
STATELY_ACCESS_KEY: ${{ secrets.STATELY_ACCESS_KEY }}
2 changes: 1 addition & 1 deletion api/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pool.on('acquire', () => {
});
pool.on('error', (e: Error) => {
metrics.increment('db.pool.error.count');
metrics.increment(`db.pool.error.${ e.name }.count`);
metrics.increment(`db.pool.error.${e.name}.count`);
});
pool.on('remove', () => {
metrics.increment('db.pool.remove.count');
Expand Down
4 changes: 2 additions & 2 deletions api/stately/apps-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export async function getAppById(id: string): Promise<ApiApp | undefined> {
*/
export async function insertApp(app: ApiApp): Promise<ApiApp> {
let resultApp: ApiApp | undefined;
// TODO: wish I could set an if-not-exists condition here, to avoid
// accidentally updating an app. Instead I got a transaction.
// We can't use `mustNotExist` here because we want to return the existing app
// on conflict.
const result = await client.transaction(async (txn) => {
const getResult = await txn.get('ApiApp', keyPathFor(app.id));
if (getResult) {
Expand Down
106 changes: 53 additions & 53 deletions api/stately/generated/stately_item_types.d.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,78 @@
// @generated by Stately. DO NOT EDIT.
/* eslint-disable */

import type { DatabaseClient as GenericDatabaseClient, StoreID, ClientOptions } from "@stately-cloud/client";
import type {
ClientOptions,
DatabaseClient as GenericDatabaseClient,
StoreID,
} from '@stately-cloud/client';
import type {
ApiApp,
GlobalSettings,
ItemAnnotation,
ItemHashTag,
Loadout,
LoadoutShare,
Search,
Settings,
Triumph,
ApiAppSchema,
GlobalSettingsSchema,
ItemAnnotationSchema,
ItemHashTagSchema,
LoadoutSchema,
LoadoutShareSchema,
SearchSchema,
SettingsSchema,
TriumphSchema,
ArtifactUnlocksSchema,
CollapsedSectionSchema,
CustomStatDefSchema,
CustomStatWeightsEntrySchema,
CustomStatsEntrySchema,
GlobalSettings,
GlobalSettingsSchema,
InGameLoadoutIdentifiersSchema,
ItemAnnotation,
ItemAnnotationSchema,
ItemHashTag,
ItemHashTagSchema,
Loadout,
LoadoutItemSchema,
LoadoutParametersSchema,
LoadoutSchema,
LoadoutShare,
LoadoutShareSchema,
ModsByBucketEntrySchema,
Search,
SearchSchema,
Settings,
SettingsSchema,
SocketOverrideSchema,
StatConstraintSchema,
StatConstraintsEntrySchema,
} from "./stately_pb.js";
Triumph,
TriumphSchema,
} from './stately_pb.js';

export declare const itemTypeToSchema: {
"ApiApp": typeof ApiAppSchema,
"GlobalSettings": typeof GlobalSettingsSchema,
"ItemAnnotation": typeof ItemAnnotationSchema,
"ItemHashTag": typeof ItemHashTagSchema,
"Loadout": typeof LoadoutSchema,
"LoadoutShare": typeof LoadoutShareSchema,
"Search": typeof SearchSchema,
"Settings": typeof SettingsSchema,
"Triumph": typeof TriumphSchema,
"ArtifactUnlocks": typeof ArtifactUnlocksSchema,
"CollapsedSection": typeof CollapsedSectionSchema,
"CustomStatDef": typeof CustomStatDefSchema,
"CustomStatWeightsEntry": typeof CustomStatWeightsEntrySchema,
"CustomStatsEntry": typeof CustomStatsEntrySchema,
"InGameLoadoutIdentifiers": typeof InGameLoadoutIdentifiersSchema,
"LoadoutItem": typeof LoadoutItemSchema,
"LoadoutParameters": typeof LoadoutParametersSchema,
"ModsByBucketEntry": typeof ModsByBucketEntrySchema,
"SocketOverride": typeof SocketOverrideSchema,
"StatConstraint": typeof StatConstraintSchema,
"StatConstraintsEntry": typeof StatConstraintsEntrySchema,
ApiApp: typeof ApiAppSchema;
GlobalSettings: typeof GlobalSettingsSchema;
ItemAnnotation: typeof ItemAnnotationSchema;
ItemHashTag: typeof ItemHashTagSchema;
Loadout: typeof LoadoutSchema;
LoadoutShare: typeof LoadoutShareSchema;
Search: typeof SearchSchema;
Settings: typeof SettingsSchema;
Triumph: typeof TriumphSchema;
ArtifactUnlocks: typeof ArtifactUnlocksSchema;
CollapsedSection: typeof CollapsedSectionSchema;
CustomStatDef: typeof CustomStatDefSchema;
CustomStatWeightsEntry: typeof CustomStatWeightsEntrySchema;
CustomStatsEntry: typeof CustomStatsEntrySchema;
InGameLoadoutIdentifiers: typeof InGameLoadoutIdentifiersSchema;
LoadoutItem: typeof LoadoutItemSchema;
LoadoutParameters: typeof LoadoutParametersSchema;
ModsByBucketEntry: typeof ModsByBucketEntrySchema;
SocketOverride: typeof SocketOverrideSchema;
StatConstraint: typeof StatConstraintSchema;
StatConstraintsEntry: typeof StatConstraintsEntrySchema;
};

// AllItemTypes is a convenience type that represents all item type names in your schema.
export type AllItemTypes =
| "ApiApp"
| "GlobalSettings"
| "ItemAnnotation"
| "ItemHashTag"
| "Loadout"
| "LoadoutShare"
| "Search"
| "Settings"
| "Triumph";
| 'ApiApp'
| 'GlobalSettings'
| 'ItemAnnotation'
| 'ItemHashTag'
| 'Loadout'
| 'LoadoutShare'
| 'Search'
| 'Settings'
| 'Triumph';

// AnyItem is a convenience type that represents any item shape in your schema.
export type AnyItem =
Expand All @@ -87,7 +90,4 @@ export type AnyItem =
export type DatabaseClient = GenericDatabaseClient<typeof itemTypeToSchema, AllItemTypes>;

// createClient creates a new database client with your schema.
export declare function createClient(
storeId: StoreID,
opts?: ClientOptions,
): DatabaseClient;
export declare function createClient(storeId: StoreID, opts?: ClientOptions): DatabaseClient;
2 changes: 1 addition & 1 deletion api/stately/generated/stately_pb.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions api/stately/item-annotations-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ export async function updateItemAnnotation(
return deleteItemAnnotation(platformMembershipId, destinyVersion, itemAnnotation.id);
}

// We want to merge the incoming values with the existing values, so we need
// to read the existing values first in a transaction.
await client.transaction(async (txn) => {
let existing = await txn.get(
'ItemAnnotation',
Expand Down
2 changes: 2 additions & 0 deletions api/stately/item-hash-tags-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export async function updateItemHashTag(
return deleteItemHashTag(platformMembershipId, itemHashTag.hash);
}

// We want to merge the incoming values with the existing values, so we need
// to read the existing values first in a transaction.
await client.transaction(async (txn) => {
let existing = await txn.get('ItemHashTag', keyFor(platformMembershipId, itemHashTag.hash));
if (!existing) {
Expand Down
17 changes: 6 additions & 11 deletions api/stately/loadout-share-queries.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { keyPath } from '@stately-cloud/client';
import { keyPath, StatelyError } from '@stately-cloud/client';
import { Loadout } from '../shapes/loadouts.js';
import { client } from './client.js';
import { LoadoutShare as StatelyLoadoutShare } from './generated/index.js';
Expand Down Expand Up @@ -47,18 +47,13 @@ export async function addLoadoutShare(
loadout: Loadout,
): Promise<void> {
const loadoutShare = convertLoadoutShareToStately(loadout, platformMembershipId, shareId);

// TODO: This would be a nice place for Stately's initialValue option which
// would guarantee uniqueness. But it'd have to support our weird shareIDs.s
await client.transaction(async (txn) => {
const existing = await txn.get('LoadoutShare', keyFor(shareId));
// We do not want to overwrite an existing share! This is another place
// where a Put-If-Not-Exists would be nice.
if (existing) {
try {
await client.put(loadoutShare, { mustNotExist: true });
} catch (e) {
if (e instanceof StatelyError && e.statelyCode === 'ConditionalCheckFailed') {
throw new LoadoutShareCollision();
}
await txn.put(loadoutShare);
});
}
}

/**
Expand Down
18 changes: 8 additions & 10 deletions api/stately/schema/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@ export const uint32 = type('uint32', FieldDescriptorProto_Type.UINT32);
// it included some signed special values.
export const LockedExoticHash = type('LockedExoticHash', FieldDescriptorProto_Type.INT64);

export const ItemID = type('ItemID', uint, { docs: 'The unique ID of an inventory item' });
/** The unique ID of an inventory item */
export const ItemID = type('ItemID', uint);

/** The hash ID of a definition */
// Manifest hashes are actually a uint32
export const HashID = type('HashID', uint32, {
docs: 'The hash ID of a definition',
});
export const HashID = type('HashID', uint32);

export const MembershipID = type('MembershipID', uint, {
docs: 'The unique ID of a Bungie.net membership',
});
export const ProfileID = type('ProfileID', uint, {
docs: 'The unique ID of a Destiny profile. These can be moved between different Bungie.net memberships.',
});
/** The unique ID of a Bungie.net membership */
export const MembershipID = type('MembershipID', uint);
/** The unique ID of a Destiny profile. These can be moved between different Bungie.net memberships. */
export const ProfileID = type('ProfileID', uint);

// This could be an enum, but it's easy enough as a constrained number.
export const DestinyVersion = type('DestinyVersion', uint32, {
Expand Down
4 changes: 2 additions & 2 deletions kubernetes/ingress-nginx-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ data:
enable-modsecurity: "true"
enable-owasp-modsecurity-crs: "false"
proxy-body-size: "2m"
use-gzip: "true"
enable-brotli: "true"
#use-gzip: "true"
#enable-brotli: "true"
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --detectOpenHandles --verbose --coverage --forceExit",
"test:watch": "jest --watch",
"eslint-inspect": "pnpm dlx @eslint/config-inspector",
"generate": "stately schema generate -l js --schema-id 8030842688320564 --version 2 api/stately/generated",
"generate": "stately schema generate -l js --schema-id 8030842688320564 api/stately/generated",
"generate-preview": "stately schema generate -l js --preview api/stately/schema/index.ts api/stately/generated",
"dim-api-types:build": "./build-dim-api-types.sh"
},
Expand All @@ -35,7 +35,7 @@
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.3.0",
"@sentry/cli": "^2.38.2",
"@stately-cloud/schema": "^0.10.0",
"@stately-cloud/schema": "^0.12.0",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.14",
Expand Down Expand Up @@ -71,7 +71,7 @@
"@google-cloud/profiler": "^6.0.2",
"@sentry/node": "^7.119.2",
"@sentry/tracing": "^7.114.0",
"@stately-cloud/client": "^0.12.0",
"@stately-cloud/client": "^0.17.0",
"bungie-api-ts": "^5.1.0",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
Expand Down
32 changes: 16 additions & 16 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 396b6e3

Please sign in to comment.