Skip to content

Commit

Permalink
Add support for creating Hyperdrive over Access configs (#6245)
Browse files Browse the repository at this point in the history
* Add support for creating Hyperdrive over Access configs

* PR Feedback
  • Loading branch information
OilyLime authored Jul 15, 2024
1 parent d497e1e commit e4abed3
Show file tree
Hide file tree
Showing 5 changed files with 318 additions and 36 deletions.
5 changes: 5 additions & 0 deletions .changeset/soft-eagles-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": minor
---

feature: Add support for Hyperdrive over Access configs
149 changes: 146 additions & 3 deletions packages/wrangler/src/__tests__/hyperdrive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,76 @@ describe("hyperdrive commands", () => {
`);
});

it("should reject a create hyperdrive command if both connection string and individual origin params are provided", async () => {
mockHyperdriveRequest();
await expect(() =>
runWrangler(
"hyperdrive create test123 --connection-string='postgresql://test:[email protected]/neondb' --host=example.com --port=5432 --database=neondb --user=test"
)
).rejects.toThrow();
expect(std.err).toMatchInlineSnapshot(`
"X [ERROR] Arguments host and connection-string are mutually exclusive
"
`);
});

it("should create a hyperdrive over access config given the right params", async () => {
mockHyperdriveRequest();
await runWrangler(
"hyperdrive create test123 --host=example.com --database=neondb --user=test --password=password --access-client-id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.access --access-client-secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
);
expect(std.out).toMatchInlineSnapshot(`
"🚧 Creating 'test123'
✅ Created new Hyperdrive config
{
\\"id\\": \\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\\",
\\"name\\": \\"test123\\",
\\"origin\\": {
\\"host\\": \\"example.com\\",
\\"database\\": \\"neondb\\",
\\"user\\": \\"test\\",
\\"access_client_id\\": \\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.access\\"
},
\\"caching\\": {
\\"disabled\\": false
}
}"
`);
});

it("should reject a create hyperdrive over access command if access client ID is set but not access client secret", async () => {
mockHyperdriveRequest();
await expect(() =>
runWrangler(
"hyperdrive create test123 --host=example.com --database=neondb --user=test --password=password --access-client-id='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.access'"
)
).rejects.toThrow();
expect(std.err).toMatchInlineSnapshot(`
"X [ERROR] Missing dependent arguments:
access-client-id -> access-client-secret
"
`);
});

it("should reject a create hyperdrive over access command if access client secret is set but not access client ID", async () => {
mockHyperdriveRequest();
await expect(() =>
runWrangler(
"hyperdrive create test123 --host=example.com --database=neondb --user=test --password=password --access-client-secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
).rejects.toThrow();
expect(std.err).toMatchInlineSnapshot(`
"X [ERROR] Missing dependent arguments:
access-client-secret -> access-client-id
"
`);
});

it("should handle listing configs", async () => {
mockHyperdriveRequest();
await runWrangler("hyperdrive list");
Expand Down Expand Up @@ -315,10 +385,10 @@ describe("hyperdrive commands", () => {
)
).rejects.toThrow();
expect(std.err).toMatchInlineSnapshot(`
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mWhen updating the origin, all of the following must be set: origin-host, origin-port, database, origin-user, origin-password[0m
"[31mX [41;31m[[41;97mERROR[41;31m][0m [1mWhen updating the origin, all of the following must be set: origin-host, database, origin-user, origin-password[0m
"
`);
"
`);
expect(std.out).toMatchInlineSnapshot(`""`);
});

Expand Down Expand Up @@ -395,6 +465,77 @@ describe("hyperdrive commands", () => {
}"
`);
});

it("should handle updating a hyperdrive to a hyperdrive over access config given the right parameters", async () => {
mockHyperdriveRequest();
await runWrangler(
"hyperdrive update xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --origin-host=example.com --database=mydb --origin-user=newuser --origin-password='passw0rd!' --access-client-id='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.access' --access-client-secret='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'"
);
expect(std.out).toMatchInlineSnapshot(`
"🚧 Updating 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
✅ Updated xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Hyperdrive config
{
\\"id\\": \\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\\",
\\"name\\": \\"test123\\",
\\"origin\\": {
\\"host\\": \\"example.com\\",
\\"database\\": \\"mydb\\",
\\"user\\": \\"newuser\\",
\\"access_client_id\\": \\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.access\\"
},
\\"caching\\": {
\\"disabled\\": false
}
}"
`);
});

it("should throw an exception when updating a hyperdrive config's origin but neither port nor access credentials are provided", async () => {
mockHyperdriveRequest();
await expect(() =>
runWrangler(
"hyperdrive update xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --origin-host=example.com --database=mydb --origin-user=newuser --origin-password='passw0rd!'"
)
).rejects.toThrow();
expect(std.err).toMatchInlineSnapshot(`
"X [ERROR] When updating the origin, either the port or the Access Client ID and Secret must be set
"
`);
expect(std.out).toMatchInlineSnapshot(`""`);
});

it("should reject an update command if the access client ID is provided but not the access client secret", async () => {
mockHyperdriveRequest();
await expect(() =>
runWrangler(
"hyperdrive update xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --origin-host=example.com --database=mydb --origin-user=newuser --origin-password='passw0rd!' --access-client-id='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.access'"
)
).rejects.toThrow();
expect(std.err).toMatchInlineSnapshot(`
"X [ERROR] Missing dependent arguments:
access-client-id -> access-client-secret
"
`);
});

it("should reject an update command if the access client secret is provided but not the access client ID", async () => {
mockHyperdriveRequest();
await expect(() =>
runWrangler(
"hyperdrive update xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --origin-host=example.com --database=mydb --origin-user=newuser --origin-password='passw0rd!' --access-client-secret='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'"
)
).rejects.toThrow();
expect(std.err).toMatchInlineSnapshot(`
"X [ERROR] Missing dependent arguments:
access-client-secret -> access-client-id
"
`);
});
});

const defaultConfig: HyperdriveConfig = {
Expand Down Expand Up @@ -437,6 +578,7 @@ function mockHyperdriveRequest() {
// @ts-expect-error This is a string
scheme: reqBody.origin.protocol,
user: reqBody.origin.user,
access_client_id: reqBody.origin.access_client_id,
},
caching: reqBody.caching,
},
Expand All @@ -462,6 +604,7 @@ function mockHyperdriveRequest() {
port: reqBody.origin.port,
database: reqBody.origin.database,
user: reqBody.origin.user,
access_client_id: reqBody.origin.access_client_id,
}
: defaultConfig.origin,
caching: reqBody.caching ?? defaultConfig.caching,
Expand Down
13 changes: 6 additions & 7 deletions packages/wrangler/src/hyperdrive/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,18 @@ export type HyperdriveConfig = {
caching: CachingOptions;
};

export type Origin = {
export type PublicOrigin = {
host?: string;
port?: number;
};

export type PublicOrigin = Origin & {
scheme?: string;
database?: string;
user?: string;
access_client_id?: string;
};

export type OriginWithPassword = PublicOrigin & {
export type OriginWithSecrets = PublicOrigin & {
password?: string;
access_client_secret?: string;
};

export type CachingOptions = {
Expand All @@ -32,13 +31,13 @@ export type CachingOptions = {

export type CreateUpdateHyperdriveBody = {
name: string;
origin: OriginWithPassword;
origin: OriginWithSecrets;
caching: CachingOptions;
};

export type PatchHyperdriveBody = {
name?: string;
origin?: OriginWithPassword;
origin?: OriginWithSecrets;
caching?: CachingOptions;
};

Expand Down
Loading

0 comments on commit e4abed3

Please sign in to comment.