Skip to content

Commit cb36d1a

Browse files
tests: Resource manager v2 testing (#86)
1 parent 5f65580 commit cb36d1a

File tree

7 files changed

+334
-201
lines changed

7 files changed

+334
-201
lines changed

src/connection/base.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const defaultResponseSettings = {
1616
normalizeData: false
1717
};
1818

19-
interface AccountInfo {
19+
export interface AccountInfo {
2020
id: string;
2121
infraVersion: number;
2222
}
@@ -52,7 +52,12 @@ export abstract class Connection {
5252

5353
abstract resolveEngineEndpoint(): Promise<string>;
5454

55-
abstract resolveAccountId(): Promise<string>;
55+
abstract resolveAccountInfo(): Promise<AccountInfo>;
56+
57+
async resolveAccountId() {
58+
const accInfo = await this.resolveAccountInfo();
59+
return accInfo.id;
60+
}
5661

5762
protected getRequestUrl(executeQueryOptions: ExecuteQueryOptions): string {
5863
const params = this.getBaseParameters(executeQueryOptions);

src/connection/connection_v1.ts

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import { ACCOUNT, ACCOUNT_BY_NAME } from "../common/api";
2-
import { Connection as BaseConnection } from "./base";
2+
import { AccountInfo, Connection as BaseConnection } from "./base";
33
import { ResourceManager } from "../service";
44

5-
export class ConnectionV1 extends BaseConnection {
6-
// Cache for resolveAccountId
7-
private accountIdCache: string | undefined;
5+
const INFRA_VERSION = 1;
86

7+
export class ConnectionV1 extends BaseConnection {
98
async resolveEngineEndpoint() {
109
const resourceManager = new ResourceManager({
1110
connection: this,
@@ -28,29 +27,27 @@ export class ConnectionV1 extends BaseConnection {
2827
return this.engineEndpoint;
2928
}
3029

31-
async resolveAccountId() {
32-
if (this.accountIdCache) {
33-
return this.accountIdCache;
34-
}
35-
const { httpClient, apiEndpoint } = this.context;
36-
const { account } = this.options;
37-
if (account) {
38-
const queryParams = new URLSearchParams({ account_name: account });
39-
const url = `${apiEndpoint}/${ACCOUNT_BY_NAME}?${queryParams}`;
40-
const { account_id } = await httpClient
41-
.request<{ account_id: string }>("GET", url)
42-
.ready();
43-
this.accountIdCache = account_id;
44-
return account_id;
45-
} else {
46-
const url = `${apiEndpoint}/${ACCOUNT}`;
47-
const {
48-
account: { id }
49-
} = await httpClient
50-
.request<{ account: { id: string } }>("GET", url)
51-
.ready();
52-
this.accountIdCache = id;
53-
return id;
30+
async resolveAccountInfo(): Promise<AccountInfo> {
31+
if (this.accountInfo === undefined) {
32+
const { httpClient, apiEndpoint } = this.context;
33+
const { account } = this.options;
34+
if (account) {
35+
const queryParams = new URLSearchParams({ account_name: account });
36+
const url = `${apiEndpoint}/${ACCOUNT_BY_NAME}?${queryParams}`;
37+
const { account_id } = await httpClient
38+
.request<{ account_id: string }>("GET", url)
39+
.ready();
40+
this.accountInfo = { id: account_id, infraVersion: INFRA_VERSION };
41+
} else {
42+
const url = `${apiEndpoint}/${ACCOUNT}`;
43+
const {
44+
account: { id }
45+
} = await httpClient
46+
.request<{ account: { id: string } }>("GET", url)
47+
.ready();
48+
this.accountInfo = { id, infraVersion: 1 };
49+
}
5450
}
51+
return this.accountInfo;
5552
}
5653
}

src/connection/connection_v2.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
QUERY_URL
1212
} from "../common/api";
1313

14-
import { Connection as BaseConnection } from "./base";
14+
import { Connection as BaseConnection, AccountInfo } from "./base";
1515
import * as path from "path";
1616

1717
export class ConnectionV2 extends BaseConnection {
@@ -126,18 +126,19 @@ export class ConnectionV2 extends BaseConnection {
126126
return res[0];
127127
}
128128

129-
async resolveAccountInfo() {
130-
const { httpClient, apiEndpoint } = this.context;
131-
const url = `${apiEndpoint}/${ACCOUNT_ID_BY_NAME(this.account)}`;
132-
const { id, infraVersion } = await httpClient
133-
.request<{ id: string; region: string; infraVersion: string }>("GET", url)
134-
.ready();
135-
return { id, infraVersion: parseInt(infraVersion ?? "1") };
136-
}
137-
138-
async resolveAccountId() {
139-
const accInfo = await this.resolveAccountInfo();
140-
return accInfo.id;
129+
async resolveAccountInfo(): Promise<AccountInfo> {
130+
if (this.accountInfo === undefined) {
131+
const { httpClient, apiEndpoint } = this.context;
132+
const url = `${apiEndpoint}/${ACCOUNT_ID_BY_NAME(this.account)}`;
133+
const { id, infraVersion } = await httpClient
134+
.request<{ id: string; region: string; infraVersion: string }>(
135+
"GET",
136+
url
137+
)
138+
.ready();
139+
this.accountInfo = { id, infraVersion: parseInt(infraVersion ?? "1") };
140+
}
141+
return this.accountInfo;
141142
}
142143

143144
async resolveEngineEndpoint() {

src/service/database/index.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,32 @@ export class DatabaseService {
5454
return databases;
5555
}
5656

57+
private validateCreateOptions(
58+
accountVersion: number,
59+
options: CreateDatabaseOptions
60+
) {
61+
if (accountVersion >= 2 && options.region) {
62+
throw new DeprecationError({
63+
message: "Region parameter is not supported for this account"
64+
});
65+
}
66+
}
67+
68+
private setDefaultCreateOptions(options: CreateDatabaseOptions) {
69+
if (options.fail_if_exists == undefined) {
70+
options.fail_if_exists = true;
71+
}
72+
}
73+
5774
async create(
5875
name: string,
5976
options: CreateDatabaseOptions = {}
6077
): Promise<DatabaseModel> {
61-
if (options.fail_if_exists == undefined) {
62-
options.fail_if_exists = true;
63-
}
78+
const accountVersion = (await this.context.connection.resolveAccountInfo())
79+
.infraVersion;
80+
this.validateCreateOptions(accountVersion, options);
81+
this.setDefaultCreateOptions(options);
82+
6483
let query = `CREATE DATABASE ${
6584
options.fail_if_exists ? "" : "IF NOT EXISTS "
6685
} "${name}"`;

src/service/engine/index.ts

Lines changed: 76 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ import { EngineStatusSummary, CreateEngineOptions, EngineType } from "./types";
77
export class EngineService {
88
context: ResourceManagerContext;
99

10-
private CREATE_PARAMETER_NAMES: string[] = [
11-
"REGION",
12-
"ENGINE_TYPE",
13-
"SPEC",
14-
"SCALE",
15-
"AUTO_STOP",
16-
"WARMUP"
17-
];
10+
private CREATE_PARAMETER_NAMES: Record<string, string> = {
11+
region: "REGION",
12+
engine_type: "ENGINE_TYPE",
13+
spec: "SPEC",
14+
scale: "SCALE",
15+
auto_stop: "AUTO_STOP",
16+
warmup: "WARMUP"
17+
};
18+
19+
private CREATE_PARAMETER_NAMES_V2: Record<string, string> = {
20+
spec: "TYPE",
21+
scale: "NODES",
22+
auto_stop: "AUTO_STOP"
23+
};
1824

1925
constructor(context: ResourceManagerContext) {
2026
this.context = context;
@@ -90,42 +96,70 @@ export class EngineService {
9096
return engines;
9197
}
9298

99+
private validateCreateOptions(
100+
accountVersion: number,
101+
options: CreateEngineOptions
102+
) {
103+
const disallowedV2Options = ["region", "engine_type", "warmup"];
104+
if (accountVersion >= 2) {
105+
// find a list of disallowed options that are set and report them in an exception
106+
const disallowedOptions = disallowedV2Options.filter(
107+
option => (options as Record<string, string>)[option] !== undefined
108+
);
109+
if (disallowedOptions.length > 0) {
110+
throw new DeprecationError({
111+
message: `The following engine options are not supported for this account: ${disallowedOptions.join(
112+
", "
113+
)}`
114+
});
115+
}
116+
}
117+
}
118+
119+
private setDefaultCreateOptions(
120+
accountVersion: number,
121+
options: CreateEngineOptions
122+
) {
123+
if (accountVersion == 1 && options.engine_type == undefined) {
124+
options.engine_type = EngineType.GENERAL_PURPOSE;
125+
}
126+
if (options.fail_if_exists == undefined) {
127+
options.fail_if_exists = true;
128+
}
129+
}
130+
93131
async create(
94132
name: string,
95133
options: CreateEngineOptions = {}
96134
): Promise<EngineModel> {
97-
if (options.fail_if_exists == undefined) {
98-
options.fail_if_exists = true;
99-
}
100-
if (options.engine_type == undefined) {
101-
options.engine_type = EngineType.GENERAL_PURPOSE;
102-
}
135+
const accountVersion = (await this.context.connection.resolveAccountInfo())
136+
.infraVersion;
137+
this.validateCreateOptions(accountVersion, options);
138+
this.setDefaultCreateOptions(accountVersion, options);
139+
140+
const { fail_if_exists, ...createOptions } = options;
141+
103142
let query = `CREATE ENGINE ${
104-
options.fail_if_exists ? "" : "IF NOT EXISTS "
143+
fail_if_exists ? "" : "IF NOT EXISTS "
105144
} "${name}"`;
106145

107-
const allParamValues = [
108-
options.region,
109-
options.engine_type,
110-
options.spec,
111-
options.scale,
112-
options.auto_stop,
113-
options.warmup
114-
];
115146
const queryParameters: (string | number)[] = [];
116-
if (
117-
options.region ||
118-
options.engine_type ||
119-
options.spec ||
120-
options.scale ||
121-
options.auto_stop ||
122-
options.warmup
123-
) {
147+
const createParameterNames =
148+
accountVersion >= 2
149+
? this.CREATE_PARAMETER_NAMES_V2
150+
: this.CREATE_PARAMETER_NAMES;
151+
152+
if (Object.values(createOptions).some(v => v !== undefined)) {
124153
query += " WITH ";
125-
for (const [index, value] of allParamValues.entries()) {
126-
if (value) {
127-
query += `${this.CREATE_PARAMETER_NAMES[index]} = ?`;
128-
queryParameters.push(value);
154+
for (const [key, value] of Object.entries(createOptions)) {
155+
if (key in createParameterNames) {
156+
if (key == "spec" && accountVersion >= 2) {
157+
// spec value is provided raw without quotes for accounts v2
158+
query += `${createParameterNames[key]} = ${value} `;
159+
} else {
160+
query += `${createParameterNames[key]} = ?`;
161+
queryParameters.push(value);
162+
}
129163
}
130164
}
131165
}
@@ -139,6 +173,13 @@ export class EngineService {
139173
engine: EngineModel | string,
140174
database: DatabaseModel | string
141175
) {
176+
const accountVersion = (await this.context.connection.resolveAccountInfo())
177+
.infraVersion;
178+
if (accountVersion >= 2) {
179+
throw new DeprecationError({
180+
message: "Attach engine is not supported for this account."
181+
});
182+
}
142183
const engine_name = engine instanceof EngineModel ? engine.name : engine;
143184
const database_name =
144185
database instanceof DatabaseModel ? database.name : database;

0 commit comments

Comments
 (0)