Files
2026-07-13 12:10:05 +08:00

141 lines
3.3 KiB
TypeScript

import retry from 'async-retry';
import type { SingleStoreRemoteDatabase } from 'drizzle-orm/singlestore-proxy';
import { drizzle as proxyDrizzle } from 'drizzle-orm/singlestore-proxy';
import * as mysql2 from 'mysql2/promise';
import { afterAll, beforeAll, beforeEach } from 'vitest';
import { skipTests } from '~/common';
import { createDockerDB, tests } from './singlestore-common';
const ENABLE_LOGGING = false;
// eslint-disable-next-line drizzle-internal/require-entity-kind
class ServerSimulator {
constructor(private db: mysql2.Connection) {}
async query(sql: string, params: any[], method: 'all' | 'execute') {
if (method === 'all') {
try {
const result = await this.db.query({
sql,
values: params,
rowsAsArray: true,
typeCast: function(field: any, next: any) {
if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') {
return field.string();
}
return next();
},
});
return { data: result[0] as any };
} catch (e: any) {
return { error: e };
}
} else if (method === 'execute') {
try {
const result = await this.db.query({
sql,
values: params,
typeCast: function(field: any, next: any) {
if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') {
return field.string();
}
return next();
},
});
return { data: result as any };
} catch (e: any) {
return { error: e };
}
} else {
return { error: 'Unknown method value' };
}
}
async migrations(queries: string[]) {
await this.db.query('START TRANSACTION');
try {
for (const query of queries) {
await this.db.query(query);
}
await this.db.query('COMMIT');
} catch (e) {
await this.db.query('ROLLBACK');
throw e;
}
return {};
}
}
let db: SingleStoreRemoteDatabase;
let client: mysql2.Connection;
let serverSimulator: ServerSimulator;
beforeAll(async () => {
let connectionString;
if (process.env['SINGLESTORE_CONNECTION_STRING']) {
connectionString = process.env['SINGLESTORE_CONNECTION_STRING'];
} else {
const { connectionString: conStr } = await createDockerDB();
connectionString = conStr;
}
client = await retry(async () => {
client = await mysql2.createConnection({ uri: connectionString, supportBigNumbers: true });
await client.connect();
return client;
}, {
retries: 20,
factor: 1,
minTimeout: 250,
maxTimeout: 250,
randomize: false,
onRetry() {
client?.end();
},
});
await client.query(`CREATE DATABASE IF NOT EXISTS drizzle;`);
await client.changeUser({ database: 'drizzle' });
serverSimulator = new ServerSimulator(client);
db = proxyDrizzle(async (sql, params, method) => {
try {
const response = await serverSimulator.query(sql, params, method);
if (response.error !== undefined) {
throw response.error;
}
return { rows: response.data };
} catch (e: any) {
console.error('Error from singlestore proxy server:', e.message);
throw e;
}
}, { logger: ENABLE_LOGGING });
});
afterAll(async () => {
await client?.end();
});
beforeEach((ctx) => {
ctx.singlestore = {
db,
};
});
skipTests([
'select iterator w/ prepared statement',
'select iterator',
'nested transaction rollback',
'nested transaction',
'transaction rollback',
'transaction',
'transaction with options (set isolationLevel)',
'migrator',
]);
tests();