From b527f9df2d05a9f3fd57115b38aad244f716f7d2 Mon Sep 17 00:00:00 2001 From: Jason Paulos Date: Wed, 12 Oct 2022 14:56:13 -0700 Subject: [PATCH] Code generation improvements for boxes (#662) --- .../v2/algod/getApplicationBoxByName.ts | 6 +- src/client/v2/algod/getApplicationBoxes.ts | 17 +- src/client/v2/algod/models/types.ts | 34 +++ src/client/v2/indexer/indexer.ts | 6 +- .../lookupApplicationBoxByIDandName.ts | 8 +- src/client/v2/indexer/models/types.ts | 193 ++++++++++++++++++ .../v2/indexer/searchForApplicationBoxes.ts | 41 +--- src/main.ts | 5 +- 8 files changed, 238 insertions(+), 72 deletions(-) diff --git a/src/client/v2/algod/getApplicationBoxByName.ts b/src/client/v2/algod/getApplicationBoxByName.ts index 7848aa98a..29e832369 100644 --- a/src/client/v2/algod/getApplicationBoxByName.ts +++ b/src/client/v2/algod/getApplicationBoxByName.ts @@ -44,10 +44,6 @@ export default class GetApplicationBoxByName extends JSONRequest< // eslint-disable-next-line class-methods-use-this prepare(body: Record): Box { - if (body.name == null) - throw new Error(`Response does not contain "name" property: ${body}`); - if (body.value == null) - throw new Error(`Response does not contain "value" property: ${body}`); - return new Box(body.name, body.value); + return Box.from_obj_for_encoding(body); } } diff --git a/src/client/v2/algod/getApplicationBoxes.ts b/src/client/v2/algod/getApplicationBoxes.ts index 10d1e9253..213c9cca7 100644 --- a/src/client/v2/algod/getApplicationBoxes.ts +++ b/src/client/v2/algod/getApplicationBoxes.ts @@ -1,7 +1,7 @@ import JSONRequest from '../jsonrequest'; import HTTPClient from '../../client'; import IntDecoding from '../../../types/intDecoding'; -import { BoxesResponse, BoxDescriptor } from './models/types'; +import { BoxesResponse } from './models/types'; /** * Given an application ID, return all the box names associated with the app. @@ -56,19 +56,6 @@ export default class GetApplicationBoxes extends JSONRequest< // eslint-disable-next-line class-methods-use-this prepare(body: Record): BoxesResponse { - if (body.boxes == null || !Array.isArray(body.boxes)) - throw new Error( - `Response does not contain "boxes" array property: ${body}` - ); - - const boxes = (body.boxes as any[]).map((box, index) => { - if (box.name == null) - throw new Error( - `Response box at index ${index} does not contain "name" property: ${box}` - ); - return new BoxDescriptor(box.name); - }); - - return new BoxesResponse(boxes); + return BoxesResponse.from_obj_for_encoding(body); } } diff --git a/src/client/v2/algod/models/types.ts b/src/client/v2/algod/models/types.ts index bfb77cefc..41c5222b7 100644 --- a/src/client/v2/algod/models/types.ts +++ b/src/client/v2/algod/models/types.ts @@ -1435,6 +1435,17 @@ export class Box extends BaseModel { value: 'value', }; } + + // eslint-disable-next-line camelcase + static from_obj_for_encoding(data: Record): Box { + /* eslint-disable dot-notation */ + if (typeof data['name'] === 'undefined') + throw new Error(`Response is missing required field 'name': ${data}`); + if (typeof data['value'] === 'undefined') + throw new Error(`Response is missing required field 'value': ${data}`); + return new Box(data['name'], data['value']); + /* eslint-enable dot-notation */ + } } /** @@ -1461,6 +1472,15 @@ export class BoxDescriptor extends BaseModel { name: 'name', }; } + + // eslint-disable-next-line camelcase + static from_obj_for_encoding(data: Record): BoxDescriptor { + /* eslint-disable dot-notation */ + if (typeof data['name'] === 'undefined') + throw new Error(`Response is missing required field 'name': ${data}`); + return new BoxDescriptor(data['name']); + /* eslint-enable dot-notation */ + } } /** @@ -1481,6 +1501,19 @@ export class BoxesResponse extends BaseModel { boxes: 'boxes', }; } + + // eslint-disable-next-line camelcase + static from_obj_for_encoding(data: Record): BoxesResponse { + /* eslint-disable dot-notation */ + if (!Array.isArray(data['boxes'])) + throw new Error( + `Response is missing required array field 'boxes': ${data}` + ); + return new BoxesResponse( + data['boxes'].map(BoxDescriptor.from_obj_for_encoding) + ); + /* eslint-enable dot-notation */ + } } export class BuildVersion extends BaseModel { @@ -2973,6 +3006,7 @@ export class StateProof extends BaseModel { typeof stateproof === 'string' ? new Uint8Array(Buffer.from(stateproof, 'base64')) : stateproof; + this.attribute_map = { message: 'Message', stateproof: 'StateProof', diff --git a/src/client/v2/indexer/indexer.ts b/src/client/v2/indexer/indexer.ts index 7fd053e24..b767343d6 100644 --- a/src/client/v2/indexer/indexer.ts +++ b/src/client/v2/indexer/indexer.ts @@ -18,17 +18,13 @@ import SearchAccounts from './searchAccounts'; import SearchForTransactions from './searchForTransactions'; import SearchForAssets from './searchForAssets'; import SearchForApplications from './searchForApplications'; -import SearchForApplicationBoxes, { - SearchForApplicationBoxesResponse, -} from './searchForApplicationBoxes'; +import SearchForApplicationBoxes from './searchForApplicationBoxes'; import { BaseHTTPClient } from '../../baseHTTPClient'; import { CustomTokenHeader, IndexerTokenHeader, } from '../../urlTokenBaseHTTPClient'; -export { SearchForApplicationBoxesResponse }; - /** * The Indexer provides a REST API interface of API calls to support searching the Algorand Blockchain. * diff --git a/src/client/v2/indexer/lookupApplicationBoxByIDandName.ts b/src/client/v2/indexer/lookupApplicationBoxByIDandName.ts index 80c069913..68b456aa8 100644 --- a/src/client/v2/indexer/lookupApplicationBoxByIDandName.ts +++ b/src/client/v2/indexer/lookupApplicationBoxByIDandName.ts @@ -1,7 +1,7 @@ import JSONRequest from '../jsonrequest'; import HTTPClient from '../../client'; import IntDecoding from '../../../types/intDecoding'; -import { Box } from '../algod/models/types'; +import { Box } from './models/types'; export default class LookupApplicationBoxByIDandName extends JSONRequest< Box, @@ -45,10 +45,6 @@ export default class LookupApplicationBoxByIDandName extends JSONRequest< // eslint-disable-next-line class-methods-use-this prepare(body: Record): Box { - if (body.name == null) - throw new Error(`Response does not contain "name" property: ${body}`); - if (body.value == null) - throw new Error(`Response does not contain "value" property: ${body}`); - return new Box(body.name, body.value); + return Box.from_obj_for_encoding(body); } } diff --git a/src/client/v2/indexer/models/types.ts b/src/client/v2/indexer/models/types.ts index 5c5948d39..7f5e417fb 100644 --- a/src/client/v2/indexer/models/types.ts +++ b/src/client/v2/indexer/models/types.ts @@ -64,6 +64,18 @@ export class Account extends BaseModel { */ public totalAssetsOptedIn: number | bigint; + /** + * For app-accounts only. The total number of bytes allocated for the keys and + * values of boxes which belong to the associated application. + */ + public totalBoxBytes: number | bigint; + + /** + * For app-accounts only. The total number of boxes which belong to the associated + * application. + */ + public totalBoxes: number | bigint; + /** * The count of all apps (AppParams objects) created by this account. */ @@ -173,6 +185,10 @@ export class Account extends BaseModel { * of application local data (AppLocalState objects) stored in this account. * @param totalAssetsOptedIn - The count of all assets that have been opted in, equivalent to the count of * AssetHolding objects held by this account. + * @param totalBoxBytes - For app-accounts only. The total number of bytes allocated for the keys and + * values of boxes which belong to the associated application. + * @param totalBoxes - For app-accounts only. The total number of boxes which belong to the associated + * application. * @param totalCreatedApps - The count of all apps (AppParams objects) created by this account. * @param totalCreatedAssets - The count of all assets (AssetParams objects) created by this account. * @param appsLocalState - (appl) applications local data stored in this account. @@ -214,6 +230,8 @@ export class Account extends BaseModel { status, totalAppsOptedIn, totalAssetsOptedIn, + totalBoxBytes, + totalBoxes, totalCreatedApps, totalCreatedAssets, appsLocalState, @@ -239,6 +257,8 @@ export class Account extends BaseModel { status: string; totalAppsOptedIn: number | bigint; totalAssetsOptedIn: number | bigint; + totalBoxBytes: number | bigint; + totalBoxes: number | bigint; totalCreatedApps: number | bigint; totalCreatedAssets: number | bigint; appsLocalState?: ApplicationLocalState[]; @@ -265,6 +285,8 @@ export class Account extends BaseModel { this.status = status; this.totalAppsOptedIn = totalAppsOptedIn; this.totalAssetsOptedIn = totalAssetsOptedIn; + this.totalBoxBytes = totalBoxBytes; + this.totalBoxes = totalBoxes; this.totalCreatedApps = totalCreatedApps; this.totalCreatedAssets = totalCreatedAssets; this.appsLocalState = appsLocalState; @@ -291,6 +313,8 @@ export class Account extends BaseModel { status: 'status', totalAppsOptedIn: 'total-apps-opted-in', totalAssetsOptedIn: 'total-assets-opted-in', + totalBoxBytes: 'total-box-bytes', + totalBoxes: 'total-boxes', totalCreatedApps: 'total-created-apps', totalCreatedAssets: 'total-created-assets', appsLocalState: 'apps-local-state', @@ -338,6 +362,14 @@ export class Account extends BaseModel { throw new Error( `Response is missing required field 'total-assets-opted-in': ${data}` ); + if (typeof data['total-box-bytes'] === 'undefined') + throw new Error( + `Response is missing required field 'total-box-bytes': ${data}` + ); + if (typeof data['total-boxes'] === 'undefined') + throw new Error( + `Response is missing required field 'total-boxes': ${data}` + ); if (typeof data['total-created-apps'] === 'undefined') throw new Error( `Response is missing required field 'total-created-apps': ${data}` @@ -356,6 +388,8 @@ export class Account extends BaseModel { status: data['status'], totalAppsOptedIn: data['total-apps-opted-in'], totalAssetsOptedIn: data['total-assets-opted-in'], + totalBoxBytes: data['total-box-bytes'], + totalBoxes: data['total-boxes'], totalCreatedApps: data['total-created-apps'], totalCreatedAssets: data['total-created-assets'], appsLocalState: @@ -2609,6 +2643,165 @@ export class BlockUpgradeVote extends BaseModel { } } +/** + * Box name and its content. + */ +export class Box extends BaseModel { + /** + * (name) box name, base64 encoded + */ + public name: Uint8Array; + + /** + * (value) box value, base64 encoded. + */ + public value: Uint8Array; + + /** + * Creates a new `Box` object. + * @param name - (name) box name, base64 encoded + * @param value - (value) box value, base64 encoded. + */ + constructor({ + name, + value, + }: { + name: string | Uint8Array; + value: string | Uint8Array; + }) { + super(); + this.name = + typeof name === 'string' + ? new Uint8Array(Buffer.from(name, 'base64')) + : name; + this.value = + typeof value === 'string' + ? new Uint8Array(Buffer.from(value, 'base64')) + : value; + + this.attribute_map = { + name: 'name', + value: 'value', + }; + } + + // eslint-disable-next-line camelcase + static from_obj_for_encoding(data: Record): Box { + /* eslint-disable dot-notation */ + if (typeof data['name'] === 'undefined') + throw new Error(`Response is missing required field 'name': ${data}`); + if (typeof data['value'] === 'undefined') + throw new Error(`Response is missing required field 'value': ${data}`); + return new Box({ + name: data['name'], + value: data['value'], + }); + /* eslint-enable dot-notation */ + } +} + +/** + * Box descriptor describes an app box without a value. + */ +export class BoxDescriptor extends BaseModel { + /** + * Base64 encoded box name + */ + public name: Uint8Array; + + /** + * Creates a new `BoxDescriptor` object. + * @param name - Base64 encoded box name + */ + constructor({ name }: { name: string | Uint8Array }) { + super(); + this.name = + typeof name === 'string' + ? new Uint8Array(Buffer.from(name, 'base64')) + : name; + + this.attribute_map = { + name: 'name', + }; + } + + // eslint-disable-next-line camelcase + static from_obj_for_encoding(data: Record): BoxDescriptor { + /* eslint-disable dot-notation */ + if (typeof data['name'] === 'undefined') + throw new Error(`Response is missing required field 'name': ${data}`); + return new BoxDescriptor({ + name: data['name'], + }); + /* eslint-enable dot-notation */ + } +} + +/** + * Box names of an application + */ +export class BoxesResponse extends BaseModel { + /** + * (appidx) application index. + */ + public applicationId: number | bigint; + + public boxes: BoxDescriptor[]; + + /** + * Used for pagination, when making another request provide this token with the + * next parameter. + */ + public nextToken?: string; + + /** + * Creates a new `BoxesResponse` object. + * @param applicationId - (appidx) application index. + * @param boxes - + * @param nextToken - Used for pagination, when making another request provide this token with the + * next parameter. + */ + constructor({ + applicationId, + boxes, + nextToken, + }: { + applicationId: number | bigint; + boxes: BoxDescriptor[]; + nextToken?: string; + }) { + super(); + this.applicationId = applicationId; + this.boxes = boxes; + this.nextToken = nextToken; + + this.attribute_map = { + applicationId: 'application-id', + boxes: 'boxes', + nextToken: 'next-token', + }; + } + + // eslint-disable-next-line camelcase + static from_obj_for_encoding(data: Record): BoxesResponse { + /* eslint-disable dot-notation */ + if (typeof data['application-id'] === 'undefined') + throw new Error( + `Response is missing required field 'application-id': ${data}` + ); + if (!Array.isArray(data['boxes'])) + throw new Error( + `Response is missing required array field 'boxes': ${data}` + ); + return new BoxesResponse({ + applicationId: data['application-id'], + boxes: data['boxes'].map(BoxDescriptor.from_obj_for_encoding), + nextToken: data['next-token'], + }); + /* eslint-enable dot-notation */ + } +} + /** * Response for errors */ diff --git a/src/client/v2/indexer/searchForApplicationBoxes.ts b/src/client/v2/indexer/searchForApplicationBoxes.ts index 6c34cb15e..b881de422 100644 --- a/src/client/v2/indexer/searchForApplicationBoxes.ts +++ b/src/client/v2/indexer/searchForApplicationBoxes.ts @@ -1,16 +1,10 @@ import JSONRequest from '../jsonrequest'; import HTTPClient from '../../client'; import IntDecoding from '../../../types/intDecoding'; -import { BoxDescriptor } from '../algod/models/types'; - -export interface SearchForApplicationBoxesResponse { - applicationId: number; - boxes: BoxDescriptor[]; - nextToken?: string; -} +import { BoxesResponse } from './models/types'; export default class SearchForApplicationBoxes extends JSONRequest< - SearchForApplicationBoxesResponse, + BoxesResponse, Record > { /** @@ -101,34 +95,7 @@ export default class SearchForApplicationBoxes extends JSONRequest< } // eslint-disable-next-line class-methods-use-this - prepare(body: Record): SearchForApplicationBoxesResponse { - if (typeof body['application-id'] !== 'number') { - throw new Error( - `Response does not contain "application-id" number property: ${body}` - ); - } - const applicationId: number = body['application-id']; - - if (body.boxes == null || !Array.isArray(body.boxes)) - throw new Error( - `Response does not contain "boxes" array property: ${body}` - ); - const boxes = (body.boxes as any[]).map((box, index) => { - if (box.name == null) - throw new Error( - `Response box at index ${index} does not contain "name" property: ${box}` - ); - return new BoxDescriptor(box.name); - }); - - const response: SearchForApplicationBoxesResponse = { - applicationId, - boxes, - }; - if (body['next-token'] != null) { - response.nextToken = body['next-token']; - } - - return response; + prepare(body: Record): BoxesResponse { + return BoxesResponse.from_obj_for_encoding(body); } } diff --git a/src/main.ts b/src/main.ts index a882391fb..4d80ec355 100644 --- a/src/main.ts +++ b/src/main.ts @@ -122,10 +122,7 @@ export { default as Algodv2 } from './client/v2/algod/algod'; export { default as Kmd } from './client/kmd'; export { default as IntDecoding } from './types/intDecoding'; export { default as Account } from './types/account'; -export { - default as Indexer, - SearchForApplicationBoxesResponse, -} from './client/v2/indexer/indexer'; +export { default as Indexer } from './client/v2/indexer/indexer'; export { BaseHTTPClient, BaseHTTPClientResponse,