Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update stately, use mustNotExist for loadout shares #251

Merged
merged 6 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

Loading