141 lines
3.3 KiB
TypeScript
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();
|