346 lines
7.7 KiB
TypeScript
346 lines
7.7 KiB
TypeScript
import Docker from 'dockerode';
|
|
import { sql } from 'drizzle-orm';
|
|
import { check, int, mysqlTable, mysqlView } from 'drizzle-orm/mysql-core';
|
|
import fs from 'fs';
|
|
import getPort from 'get-port';
|
|
import { Connection, createConnection } from 'mysql2/promise';
|
|
import { diffTestSchemasPushMysql } from 'tests/schemaDiffer';
|
|
import { v4 as uuid } from 'uuid';
|
|
import { afterAll, beforeAll, expect, test } from 'vitest';
|
|
|
|
let client: Connection;
|
|
let mysqlContainer: Docker.Container;
|
|
|
|
async function createDockerDB(): Promise<string> {
|
|
const docker = new Docker();
|
|
const port = await getPort({ port: 3306 });
|
|
const image = 'mysql:8';
|
|
|
|
const pullStream = await docker.pull(image);
|
|
await new Promise((resolve, reject) =>
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err))
|
|
);
|
|
|
|
mysqlContainer = await docker.createContainer({
|
|
Image: image,
|
|
Env: ['MYSQL_ROOT_PASSWORD=mysql', 'MYSQL_DATABASE=drizzle'],
|
|
name: `drizzle-integration-tests-${uuid()}`,
|
|
HostConfig: {
|
|
AutoRemove: true,
|
|
PortBindings: {
|
|
'3306/tcp': [{ HostPort: `${port}` }],
|
|
},
|
|
},
|
|
});
|
|
|
|
await mysqlContainer.start();
|
|
|
|
return `mysql://root:mysql@127.0.0.1:${port}/drizzle`;
|
|
}
|
|
|
|
beforeAll(async () => {
|
|
const connectionString = process.env.MYSQL_CONNECTION_STRING ?? await createDockerDB();
|
|
|
|
const sleep = 1000;
|
|
let timeLeft = 20000;
|
|
let connected = false;
|
|
let lastError: unknown | undefined;
|
|
do {
|
|
try {
|
|
client = await createConnection(connectionString);
|
|
await client.connect();
|
|
connected = true;
|
|
break;
|
|
} catch (e) {
|
|
lastError = e;
|
|
await new Promise((resolve) => setTimeout(resolve, sleep));
|
|
timeLeft -= sleep;
|
|
}
|
|
} while (timeLeft > 0);
|
|
if (!connected) {
|
|
console.error('Cannot connect to MySQL');
|
|
await client?.end().catch(console.error);
|
|
await mysqlContainer?.stop().catch(console.error);
|
|
throw lastError;
|
|
}
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await client?.end().catch(console.error);
|
|
await mysqlContainer?.stop().catch(console.error);
|
|
});
|
|
|
|
if (!fs.existsSync('tests/push/mysql')) {
|
|
fs.mkdirSync('tests/push/mysql');
|
|
}
|
|
|
|
test('add check constraint to table', async () => {
|
|
const schema1 = {
|
|
test: mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
values: int('values'),
|
|
}),
|
|
};
|
|
const schema2 = {
|
|
test: mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
values: int('values'),
|
|
}, (table) => ({
|
|
checkConstraint1: check('some_check1', sql`${table.values} < 100`),
|
|
checkConstraint2: check('some_check2', sql`'test' < 100`),
|
|
})),
|
|
};
|
|
|
|
const { statements, sqlStatements } = await diffTestSchemasPushMysql(
|
|
client,
|
|
schema1,
|
|
schema2,
|
|
[],
|
|
'drizzle',
|
|
false,
|
|
);
|
|
|
|
expect(statements).toStrictEqual([
|
|
{
|
|
type: 'create_check_constraint',
|
|
tableName: 'test',
|
|
schema: '',
|
|
data: 'some_check1;\`test\`.\`values\` < 100',
|
|
},
|
|
{
|
|
data: "some_check2;'test' < 100",
|
|
schema: '',
|
|
tableName: 'test',
|
|
type: 'create_check_constraint',
|
|
},
|
|
]);
|
|
expect(sqlStatements).toStrictEqual([
|
|
'ALTER TABLE \`test\` ADD CONSTRAINT \`some_check1\` CHECK (\`test\`.\`values\` < 100);',
|
|
`ALTER TABLE \`test\` ADD CONSTRAINT \`some_check2\` CHECK ('test' < 100);`,
|
|
]);
|
|
|
|
await client.query(`DROP TABLE \`test\`;`);
|
|
});
|
|
|
|
test('drop check constraint to table', async () => {
|
|
const schema1 = {
|
|
test: mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
values: int('values'),
|
|
}, (table) => ({
|
|
checkConstraint1: check('some_check1', sql`${table.values} < 100`),
|
|
checkConstraint2: check('some_check2', sql`'test' < 100`),
|
|
})),
|
|
};
|
|
const schema2 = {
|
|
test: mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
values: int('values'),
|
|
}),
|
|
};
|
|
|
|
const { statements, sqlStatements } = await diffTestSchemasPushMysql(
|
|
client,
|
|
schema1,
|
|
schema2,
|
|
[],
|
|
'drizzle',
|
|
false,
|
|
);
|
|
|
|
expect(statements).toStrictEqual([
|
|
{
|
|
type: 'delete_check_constraint',
|
|
tableName: 'test',
|
|
schema: '',
|
|
constraintName: 'some_check1',
|
|
},
|
|
{
|
|
constraintName: 'some_check2',
|
|
schema: '',
|
|
tableName: 'test',
|
|
type: 'delete_check_constraint',
|
|
},
|
|
]);
|
|
expect(sqlStatements).toStrictEqual([
|
|
'ALTER TABLE \`test\` DROP CONSTRAINT \`some_check1\`;',
|
|
`ALTER TABLE \`test\` DROP CONSTRAINT \`some_check2\`;`,
|
|
]);
|
|
|
|
await client.query(`DROP TABLE \`test\`;`);
|
|
});
|
|
|
|
test('db has checks. Push with same names', async () => {
|
|
const schema1 = {
|
|
test: mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
values: int('values').default(1),
|
|
}, (table) => ({
|
|
checkConstraint: check('some_check', sql`${table.values} < 100`),
|
|
})),
|
|
};
|
|
const schema2 = {
|
|
test: mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
values: int('values').default(1),
|
|
}, (table) => ({
|
|
checkConstraint: check('some_check', sql`some new value`),
|
|
})),
|
|
};
|
|
|
|
const { statements, sqlStatements } = await diffTestSchemasPushMysql(
|
|
client,
|
|
schema1,
|
|
schema2,
|
|
[],
|
|
'drizzle',
|
|
);
|
|
|
|
expect(statements).toStrictEqual([]);
|
|
expect(sqlStatements).toStrictEqual([]);
|
|
|
|
await client.query(`DROP TABLE \`test\`;`);
|
|
});
|
|
|
|
test('create view', async () => {
|
|
const table = mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
});
|
|
|
|
const schema1 = {
|
|
test: table,
|
|
};
|
|
|
|
const schema2 = {
|
|
test: table,
|
|
view: mysqlView('view').as((qb) => qb.select().from(table)),
|
|
};
|
|
|
|
const { statements, sqlStatements } = await diffTestSchemasPushMysql(
|
|
client,
|
|
schema1,
|
|
schema2,
|
|
[],
|
|
'drizzle',
|
|
false,
|
|
);
|
|
|
|
expect(statements).toStrictEqual([
|
|
{
|
|
definition: 'select \`id\` from \`test\`',
|
|
name: 'view',
|
|
type: 'mysql_create_view',
|
|
replace: false,
|
|
sqlSecurity: 'definer',
|
|
withCheckOption: undefined,
|
|
algorithm: 'undefined',
|
|
},
|
|
]);
|
|
expect(sqlStatements).toStrictEqual([
|
|
`CREATE ALGORITHM = undefined
|
|
SQL SECURITY definer
|
|
VIEW \`view\` AS (select \`id\` from \`test\`);`,
|
|
]);
|
|
|
|
await client.query(`DROP TABLE \`test\`;`);
|
|
});
|
|
|
|
test('drop view', async () => {
|
|
const table = mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
});
|
|
|
|
const schema1 = {
|
|
test: table,
|
|
view: mysqlView('view').as((qb) => qb.select().from(table)),
|
|
};
|
|
|
|
const schema2 = {
|
|
test: table,
|
|
};
|
|
|
|
const { statements, sqlStatements } = await diffTestSchemasPushMysql(
|
|
client,
|
|
schema1,
|
|
schema2,
|
|
[],
|
|
'drizzle',
|
|
false,
|
|
);
|
|
|
|
expect(statements).toStrictEqual([
|
|
{
|
|
name: 'view',
|
|
type: 'drop_view',
|
|
},
|
|
]);
|
|
expect(sqlStatements).toStrictEqual([
|
|
'DROP VIEW \`view\`;',
|
|
]);
|
|
await client.query(`DROP TABLE \`test\`;`);
|
|
await client.query(`DROP VIEW \`view\`;`);
|
|
});
|
|
|
|
test('alter view ".as"', async () => {
|
|
const table = mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
});
|
|
|
|
const schema1 = {
|
|
test: table,
|
|
view: mysqlView('view').as((qb) => qb.select().from(table).where(sql`${table.id} = 1`)),
|
|
};
|
|
|
|
const schema2 = {
|
|
test: table,
|
|
view: mysqlView('view').as((qb) => qb.select().from(table)),
|
|
};
|
|
|
|
const { statements, sqlStatements } = await diffTestSchemasPushMysql(
|
|
client,
|
|
schema1,
|
|
schema2,
|
|
[],
|
|
'drizzle',
|
|
false,
|
|
);
|
|
|
|
expect(statements.length).toBe(0);
|
|
expect(sqlStatements.length).toBe(0);
|
|
|
|
await client.query(`DROP TABLE \`test\`;`);
|
|
await client.query(`DROP VIEW \`view\`;`);
|
|
});
|
|
|
|
test('alter meta options with distinct in definition', async () => {
|
|
const table = mysqlTable('test', {
|
|
id: int('id').primaryKey(),
|
|
});
|
|
|
|
const schema1 = {
|
|
test: table,
|
|
view: mysqlView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('merge').as((
|
|
qb,
|
|
) => qb.selectDistinct().from(table).where(sql`${table.id} = 1`)),
|
|
};
|
|
|
|
const schema2 = {
|
|
test: table,
|
|
view: mysqlView('view').withCheckOption('cascaded').sqlSecurity('definer').algorithm('undefined').as((qb) =>
|
|
qb.selectDistinct().from(table)
|
|
),
|
|
};
|
|
|
|
await expect(diffTestSchemasPushMysql(
|
|
client,
|
|
schema1,
|
|
schema2,
|
|
[],
|
|
'drizzle',
|
|
false,
|
|
)).rejects.toThrowError();
|
|
|
|
await client.query(`DROP TABLE \`test\`;`);
|
|
});
|