Skip to content

Commit

Permalink
Move rawParse/Execute methods to AdminFetchConn + add ability to prov…
Browse files Browse the repository at this point in the history
…ide AbortSignal (#707)
  • Loading branch information
jaclarke authored Sep 18, 2023
1 parent 95eeee7 commit 09dc5d3
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 117 deletions.
60 changes: 2 additions & 58 deletions packages/driver/src/baseConn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,13 @@ new DataView(NO_TRANSACTION_CAPABILITIES_BYTES.buffer).setUint32(
NO_TRANSACTION_CAPABILITIES
);

const RESTRICTED_CAPABILITIES =
export const RESTRICTED_CAPABILITIES =
(Capabilities.ALL &
~Capabilities.TRANSACTION &
~Capabilities.SESSION_CONFIG &
~Capabilities.SET_GLOBAL) >>>
0;

const STUDIO_CAPABILITIES =
(RESTRICTED_CAPABILITIES |
Capabilities.SESSION_CONFIG |
Capabilities.SET_GLOBAL) >>>
0;

enum CompilationFlag {
INJECT_OUTPUT_TYPE_IDS = 1 << 0,
INJECT_OUTPUT_TYPE_NAMES = 1 << 1,
Expand Down Expand Up @@ -1038,7 +1032,7 @@ export class BaseRawConnection {
];
}

private async _executeFlow(
protected async _executeFlow(
query: string,
args: QueryArgs,
outputFormat: OutputFormat,
Expand Down Expand Up @@ -1447,54 +1441,4 @@ export class BaseRawConnection {
async close(): Promise<void> {
this._abort();
}

// These methods are exposed for use by EdgeDB Studio
public async rawParse(
query: string,
state: Session,
options?: QueryOptions
): Promise<
[ICodec, ICodec, Uint8Array, Uint8Array, ProtocolVersion, number]
> {
const result = (await this._parse(
query,
OutputFormat.BINARY,
Cardinality.MANY,
state,
STUDIO_CAPABILITIES,
options
))!;
return [
result[1],
result[2],
result[4]!,
result[5]!,
this.protocolVersion,
result[3],
];
}

public async rawExecute(
query: string,
state: Session,
outCodec?: ICodec,
options?: QueryOptions,
inCodec?: ICodec,
args: QueryArgs = null
): Promise<Uint8Array> {
const result = new WriteBuffer();
await this._executeFlow(
query,
args,
outCodec ? OutputFormat.BINARY : OutputFormat.NONE,
Cardinality.MANY,
state,
inCodec ?? NULL_CODEC,
outCodec ?? NULL_CODEC,
result,
STUDIO_CAPABILITIES,
options
);
return result.unwrap();
}
}
93 changes: 87 additions & 6 deletions packages/driver/src/fetchConn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,29 @@
* limitations under the License.
*/

import {
BaseRawConnection,
Capabilities,
PROTO_VER,
RESTRICTED_CAPABILITIES,
} from "./baseConn";
import { NULL_CODEC } from "./codecs/codecs";
import { ICodec } from "./codecs/ifaces";
import { CodecsRegistry } from "./codecs/registry";
import { Address, NormalizedConnectConfig } from "./conUtils";
import { PROTO_VER, BaseRawConnection } from "./baseConn";
import Event from "./primitives/event";
import * as chars from "./primitives/chars";
import { InternalClientError, ProtocolError } from "./errors";
import type { HttpSCRAMAuth } from "./httpScram";
import {
Cardinality,
OutputFormat,
ProtocolVersion,
QueryArgs,
QueryOptions,
} from "./ifaces";
import { Session } from "./options";
import { WriteBuffer } from "./primitives/buffer";
import * as chars from "./primitives/chars";
import Event from "./primitives/event";

interface FetchConfig {
address: Address | string;
Expand All @@ -34,9 +50,16 @@ interface FetchConfig {

const PROTO_MIME = `application/x.edgedb.v_${PROTO_VER[0]}_${PROTO_VER[1]}.binary'`;

const STUDIO_CAPABILITIES =
(RESTRICTED_CAPABILITIES |
Capabilities.SESSION_CONFIG |
Capabilities.SET_GLOBAL) >>>
0;

class BaseFetchConnection extends BaseRawConnection {
protected config: FetchConfig;
protected addr: string;
protected abortSignal: AbortSignal | null = null;

constructor(config: FetchConfig, registry: CodecsRegistry) {
super(registry);
Expand Down Expand Up @@ -96,6 +119,7 @@ class BaseFetchConnection extends BaseRawConnection {
method: "post",
body: data,
headers,
signal: this.abortSignal,
});

if (!resp.ok) {
Expand Down Expand Up @@ -129,16 +153,17 @@ class BaseFetchConnection extends BaseRawConnection {
this.__sendData(data);
}

static create(
static create<T extends typeof BaseFetchConnection>(
this: T,
config: FetchConfig,
registry: CodecsRegistry
): BaseFetchConnection {
): InstanceType<T> {
const conn = new this(config, registry);

conn.connected = true;
conn.connWaiter.set();

return conn;
return conn as InstanceType<T>;
}
}

Expand All @@ -158,6 +183,62 @@ export class AdminUIFetchConnection extends BaseFetchConnection {
const baseUrl = `${protocol}://${address[0]}:${address[1]}`;
return `${baseUrl}/db/${database}`;
}

// These methods are exposed for use by EdgeDB Studio
public async rawParse(
query: string,
state: Session,
options?: QueryOptions,
abortSignal?: AbortSignal | null
): Promise<
[ICodec, ICodec, Uint8Array, Uint8Array, ProtocolVersion, number]
> {
this.abortSignal = abortSignal ?? null;

const result = (await this._parse(
query,
OutputFormat.BINARY,
Cardinality.MANY,
state,
STUDIO_CAPABILITIES,
options
))!;
return [
result[1],
result[2],
result[4]!,
result[5]!,
this.protocolVersion,
result[3],
];
}

public async rawExecute(
query: string,
state: Session,
outCodec?: ICodec,
options?: QueryOptions,
inCodec?: ICodec,
args: QueryArgs = null,
abortSignal?: AbortSignal | null
): Promise<Uint8Array> {
this.abortSignal = abortSignal ?? null;

const result = new WriteBuffer();
await this._executeFlow(
query,
args,
outCodec ? OutputFormat.BINARY : OutputFormat.NONE,
Cardinality.MANY,
state,
inCodec ?? NULL_CODEC,
outCodec ?? NULL_CODEC,
result,
STUDIO_CAPABILITIES,
options
);
return result.unwrap();
}
}

const _tokens = new WeakMap<NormalizedConnectConfig, string>();
Expand Down
53 changes: 12 additions & 41 deletions packages/driver/test/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ import {
InvalidReferenceError,
} from "../src/index.node";

import { retryingConnect } from "../src/retry";
import { RawConnection } from "../src/rawConn";
import { AdminUIFetchConnection } from "../src/fetchConn";
import { CustomCodecSpec } from "../src/codecs/registry";
import {
Expand All @@ -52,6 +50,8 @@ import {
isDeno,
} from "./testbase";
import { PG_VECTOR_MAX_DIM } from "../src/codecs/pgvector";
import { getHTTPSCRAMAuth } from "../src/httpScram";
import cryptoUtils from "../src/adapter.crypto.node";

function setCustomCodecs(codecs: (keyof CustomCodecSpec)[], client: Client) {
// @ts-ignore
Expand Down Expand Up @@ -2041,53 +2041,24 @@ function _decodeResultBuffer(outCodec: _ICodec, resultData: Uint8Array) {
return result;
}

// 'raw' methods are only used by edgedb studio, so only need to work with
// EdgeDB 2.0 or greater
if (getEdgeDBVersion().major >= 2) {
test("'implicit*' headers", async () => {
const config = await parseConnectArguments(getConnectOptions());
const registry = new _CodecsRegistry();
const con = await retryingConnect(
RawConnection.connectWithTimeout.bind(RawConnection),
config,
registry
);
try {
const query = `SELECT Function {
name
}`;
const state = new Session({ module: "schema" });
const options = {
injectTypenames: true,
implicitLimit: BigInt(5),
} as const;
const [_, outCodec] = await con.rawParse(query, state, options);
const resultData = await con.rawExecute(query, state, outCodec, options);

const result = _decodeResultBuffer(outCodec, resultData);

expect(result).toHaveLength(5);
expect(result[0]["__tname__"]).toBe("schema::Function");
} finally {
await con.close();
}
});
}

if (!isDeno && getAvailableFeatures().has("binary-over-http")) {
// @ts-ignore // make deno ignore skip
test.skip("binary protocol over http", async () => {
//@ts-ignore
const tokenFile = require("path").join(__dirname, "keys", "jwt");
//@ts-ignore
const token = require("fs").readFileSync(tokenFile, "utf8").trim();
test("binary protocol over http", async () => {
const codecsRegistry = new _CodecsRegistry();
const config = await parseConnectArguments(getConnectOptions());

const { address, user, password } = config.connectionParams;
const token = await getHTTPSCRAMAuth(cryptoUtils)(
`http://${address[0]}:${address[1]}`,
user,
password!
);

const fetchConn = AdminUIFetchConnection.create(
{
address: config.connectionParams.address,
database: config.connectionParams.database,
user: config.connectionParams.user,
tlsSecurity: "insecure",
token: token,
},
codecsRegistry
Expand Down
1 change: 0 additions & 1 deletion packages/driver/test/keys/jwt

This file was deleted.

5 changes: 0 additions & 5 deletions packages/driver/test/keys/private.pem

This file was deleted.

4 changes: 0 additions & 4 deletions packages/driver/test/keys/public.pem

This file was deleted.

2 changes: 0 additions & 2 deletions packages/driver/test/testUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ export const getServerCommand = (

if (help.includes("--admin-ui")) {
args.push("--http-endpoint-security=optional");
// args.push("--jws-key-file", path.join(__dirname, "keys", "public.pem"));
// args.push("--jwe-key-file", path.join(__dirname, "keys", "private.pem"));
args.push("--jose-key-mode=generate");

availableFeatures.push("binary-over-http");
Expand Down

0 comments on commit 09dc5d3

Please sign in to comment.