diff --git a/packages/client/src/api/client.test.ts b/packages/client/src/api/client.test.ts index b6ac59138..a95fd26b1 100644 --- a/packages/client/src/api/client.test.ts +++ b/packages/client/src/api/client.test.ts @@ -24,3 +24,13 @@ describe('API Proxy types', () => { expect(xata.authentication.undefinedOperation).toBeUndefined(); }); }); + +describe('XataApiClient', () => { + test('accepts and uses postgresConnectionString', () => { + const postgresConnectionString = 'postgres://user:password@localhost:5432/mydb'; + const client = new XataApiClient({ apiKey: 'fake-api-key', postgresConnectionString }); + + // @ts-ignore + expect(client.postgresConnectionString).toBe(postgresConnectionString); + }); +}); diff --git a/packages/client/src/api/client.ts b/packages/client/src/api/client.ts index 079b73f31..b7bb8d629 100644 --- a/packages/client/src/api/client.ts +++ b/packages/client/src/api/client.ts @@ -15,6 +15,7 @@ export interface XataApiClientOptions { trace?: TraceFunction; clientName?: string; xataAgentExtra?: Record; + postgresConnectionString?: string; // Pe028 } type UserProps = { @@ -42,6 +43,7 @@ const buildApiClient = () => const apiKey = options.apiKey; const trace = options.trace ?? defaultTrace; const clientID = generateUUID(); + const postgresConnectionString = options.postgresConnectionString; // Pbb35 if (!apiKey) { throw new Error('Could not resolve a valid apiKey'); @@ -55,7 +57,8 @@ const buildApiClient = () => trace, clientName: options.clientName, xataAgentExtra: options.xataAgentExtra, - clientID + clientID, + postgresConnectionString // Pbb35 }; return new Proxy(this, { diff --git a/packages/client/src/client.test.ts b/packages/client/src/client.test.ts new file mode 100644 index 000000000..758e8a9ad --- /dev/null +++ b/packages/client/src/client.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, test } from 'vitest'; +import { BaseClient } from './client'; +import { DatabaseSchema } from './schema'; + +const schema: DatabaseSchema = { + tables: [] +}; + +describe('BaseClient', () => { + test('accepts and uses postgresConnectionString', () => { + const postgresConnectionString = 'postgres://user:password@localhost:5432/mydb'; + const client = new BaseClient({ apiKey: 'fake-api-key', databaseURL: 'https://example.xata.sh/db', branch: 'main', postgresConnectionString }, schema); + + // @ts-ignore + expect(client.#options.postgresConnectionString).toBe(postgresConnectionString); + }); +}); diff --git a/packages/client/src/client.ts b/packages/client/src/client.ts index e1f21c24b..14f3da486 100644 --- a/packages/client/src/client.ts +++ b/packages/client/src/client.ts @@ -19,6 +19,7 @@ export type BaseClientOptions = { enableBrowser?: boolean; clientName?: string; xataAgentExtra?: Record; + postgresConnectionString?: string; }; type SafeOptions = AllRequired> & { @@ -95,6 +96,7 @@ export const buildClient = = {}>(plu const clientName = options?.clientName; const host = options?.host ?? 'production'; const xataAgentExtra = options?.xataAgentExtra; + const postgresConnectionString = options?.postgresConnectionString; if (!apiKey) { throw new Error('Option apiKey is required'); @@ -118,7 +120,8 @@ export const buildClient = = {}>(plu clientID: generateUUID(), enableBrowser, clientName, - xataAgentExtra + xataAgentExtra, + postgresConnectionString }; } @@ -130,7 +133,8 @@ export const buildClient = = {}>(plu trace, clientID, clientName, - xataAgentExtra + xataAgentExtra, + postgresConnectionString }: SafeOptions): ApiExtraProps { return { fetch, @@ -145,7 +149,8 @@ export const buildClient = = {}>(plu trace, clientID, clientName, - xataAgentExtra + xataAgentExtra, + postgresConnectionString }; } } as unknown as ClientConstructor; diff --git a/packages/client/src/kysely/index.ts b/packages/client/src/kysely/index.ts index 2395d2554..dcd9d5f16 100644 --- a/packages/client/src/kysely/index.ts +++ b/packages/client/src/kysely/index.ts @@ -11,7 +11,7 @@ export class KyselyPlugin> extends Xa const xata = { sql: new SQLPlugin().build(pluginOptions) }; return new Kysely>({ - dialect: new XataDialect({ xata }) + dialect: new XataDialect({ xata, postgresConnectionString: pluginOptions.postgresConnectionString }) }); } } diff --git a/packages/plugin-client-kysely/src/driver.ts b/packages/plugin-client-kysely/src/driver.ts index 756d06654..f9146a945 100644 --- a/packages/plugin-client-kysely/src/driver.ts +++ b/packages/plugin-client-kysely/src/driver.ts @@ -19,13 +19,17 @@ export type XataDialectConfig = { * @default 'strong' */ consistency?: 'strong' | 'eventual'; + postgresConnectionString?: string; }; export class XataDialect implements Dialect { constructor(private config: XataDialectConfig) {} createAdapter() { - return new PostgresAdapter(); + if (this.config.postgresConnectionString) { + return new PostgresAdapter(); + } + return new XataAdapter(); } createDriver(): Driver { @@ -84,6 +88,21 @@ export class XataConnection implements DatabaseConnection { const { sql } = this.#config.xata; const { sql: statement, parameters } = compiledQuery; + if (this.#config.postgresConnectionString) { + const { Client } = require('pg'); + const client = new Client({ connectionString: this.#config.postgresConnectionString }); + await client.connect(); + const res = await client.query(statement, parameters); + await client.end(); + + return { + rows: res.rows as O[], + columns: res.fields, + numAffectedRows: BigInt(res.rowCount), + numUpdatedOrDeletedRows: BigInt(res.rowCount) + }; + } + const { records, warning, columns } = await sql({ statement, params: parameters as any[], @@ -97,11 +116,8 @@ export class XataConnection implements DatabaseConnection { return { rows: records as O[], - // @ts-ignore columns, - // @ts-ignore replaces `QueryResult.numUpdatedOrDeletedRows` in kysely > 0.22 numAffectedRows, - // deprecated in kysely > 0.22, keep for backward compatibility. numUpdatedOrDeletedRows: numAffectedRows }; }