0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-02-10 22:38:53 -05:00
astro/packages/db/test/unit/reference-queries.test.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

178 lines
6 KiB
JavaScript
Raw Normal View History

import { expect } from 'chai';
import { describe, it } from 'mocha';
import { getCollectionChangeQueries } from '../../dist/core/cli/migration-queries.js';
2024-02-08 16:29:16 -05:00
import { field, defineCollection, collectionsSchema } from '../../dist/core/types.js';
2024-02-08 16:29:16 -05:00
const BaseUser = defineCollection({
fields: {
id: field.number({ primaryKey: true }),
name: field.text(),
age: field.number(),
email: field.text({ unique: true }),
mi: field.text({ optional: true }),
},
});
2024-02-08 16:29:16 -05:00
const BaseSentBox = defineCollection({
fields: {
2024-02-08 16:29:16 -05:00
to: field.number(),
2024-02-06 17:27:50 -05:00
toName: field.text(),
subject: field.text(),
body: field.text(),
},
});
const defaultAmbiguityResponses = {
collectionRenames: {},
fieldRenames: {},
};
2024-02-08 16:29:16 -05:00
/**
* @typedef {import('../../dist/core/types.js').DBCollection} DBCollection
* @param {{ User: DBCollection, SentBox: DBCollection }} params
* @returns
*/
function resolveReferences(
{ User = BaseUser, SentBox = BaseSentBox } = {
User: BaseUser,
SentBox: BaseSentBox,
}
) {
return collectionsSchema.parse({ User, SentBox });
}
function userChangeQueries(
oldCollection,
newCollection,
ambiguityResponses = defaultAmbiguityResponses
) {
return getCollectionChangeQueries({
collectionName: 'User',
oldCollection,
newCollection,
ambiguityResponses,
});
}
describe('reference queries', () => {
it('adds references with lossless table recreate', async () => {
2024-02-08 16:29:16 -05:00
const { SentBox: Initial } = resolveReferences();
const { SentBox: Final } = resolveReferences({
SentBox: defineCollection({
2024-02-06 17:27:50 -05:00
fields: {
2024-02-08 16:29:16 -05:00
...BaseSentBox.fields,
to: field.number({ references: () => BaseUser.fields.id }),
2024-02-06 17:27:50 -05:00
},
2024-02-08 16:29:16 -05:00
}),
});
2024-02-06 17:27:50 -05:00
2024-02-08 16:29:16 -05:00
const { queries } = await userChangeQueries(Initial, Final);
2024-02-06 17:27:50 -05:00
expect(queries[0]).to.not.be.undefined;
const tempTableName = getTempTableName(queries[0]);
2024-02-08 16:29:16 -05:00
expect(tempTableName).to.not.be.undefined;
2024-02-06 17:27:50 -05:00
expect(queries).to.deep.equal([
2024-02-08 16:29:16 -05:00
`CREATE TABLE \"${tempTableName}\" (_id INTEGER PRIMARY KEY, \"to\" integer NOT NULL REFERENCES \"User\" (\"id\"), \"toName\" text NOT NULL, \"subject\" text NOT NULL, \"body\" text NOT NULL)`,
2024-02-06 17:27:50 -05:00
`INSERT INTO \"${tempTableName}\" (\"_id\", \"to\", \"toName\", \"subject\", \"body\") SELECT \"_id\", \"to\", \"toName\", \"subject\", \"body\" FROM \"User\"`,
'DROP TABLE "User"',
`ALTER TABLE \"${tempTableName}\" RENAME TO \"User\"`,
]);
});
it('removes references with lossless table recreate', async () => {
2024-02-08 16:29:16 -05:00
const { SentBox: Initial } = resolveReferences({
SentBox: defineCollection({
fields: {
2024-02-08 16:29:16 -05:00
...BaseSentBox.fields,
to: field.number({ references: () => BaseUser.fields.id }),
},
2024-02-08 16:29:16 -05:00
}),
});
const { SentBox: Final } = resolveReferences();
2024-02-08 16:29:16 -05:00
const { queries } = await userChangeQueries(Initial, Final);
expect(queries[0]).to.not.be.undefined;
const tempTableName = getTempTableName(queries[0]);
2024-02-08 16:29:16 -05:00
expect(tempTableName).to.not.be.undefined;
expect(queries).to.deep.equal([
2024-02-08 16:29:16 -05:00
`CREATE TABLE \"${tempTableName}\" (_id INTEGER PRIMARY KEY, \"to\" integer NOT NULL, \"toName\" text NOT NULL, \"subject\" text NOT NULL, \"body\" text NOT NULL)`,
2024-02-06 17:27:50 -05:00
`INSERT INTO \"${tempTableName}\" (\"_id\", \"to\", \"toName\", \"subject\", \"body\") SELECT \"_id\", \"to\", \"toName\", \"subject\", \"body\" FROM \"User\"`,
'DROP TABLE "User"',
`ALTER TABLE \"${tempTableName}\" RENAME TO \"User\"`,
]);
});
2024-02-06 17:27:50 -05:00
it('does not use ADD COLUMN when adding optional column with reference', async () => {
2024-02-08 16:29:16 -05:00
const { SentBox: Initial } = resolveReferences();
const { SentBox: Final } = resolveReferences({
SentBox: defineCollection({
fields: {
2024-02-08 16:29:16 -05:00
...BaseSentBox.fields,
from: field.number({ references: () => BaseUser.fields.id, optional: true }),
},
2024-02-08 16:29:16 -05:00
}),
});
2024-02-08 16:29:16 -05:00
const { queries } = await userChangeQueries(Initial, Final);
expect(queries[0]).to.not.be.undefined;
const tempTableName = getTempTableName(queries[0]);
expect(queries).to.deep.equal([
2024-02-08 16:29:16 -05:00
`CREATE TABLE \"${tempTableName}\" (_id INTEGER PRIMARY KEY, \"to\" integer NOT NULL, \"toName\" text NOT NULL, \"subject\" text NOT NULL, \"body\" text NOT NULL, \"from\" integer REFERENCES \"User\" (\"id\"))`,
2024-02-06 17:27:50 -05:00
`INSERT INTO \"${tempTableName}\" (\"_id\", \"to\", \"toName\", \"subject\", \"body\") SELECT \"_id\", \"to\", \"toName\", \"subject\", \"body\" FROM \"User\"`,
'DROP TABLE "User"',
`ALTER TABLE \"${tempTableName}\" RENAME TO \"User\"`,
]);
});
2024-02-06 17:27:50 -05:00
it('adds and updates foreign key with lossless table recreate', async () => {
2024-02-08 16:29:16 -05:00
const { SentBox: InitialWithoutFK } = resolveReferences();
const { SentBox: InitialWithDifferentFK } = resolveReferences({
SentBox: defineCollection({
...BaseSentBox,
foreignKeys: [{ fields: ['to'], references: () => [BaseUser.fields.id] }],
}),
});
const { SentBox: Final } = resolveReferences({
SentBox: defineCollection({
...BaseSentBox,
2024-02-06 17:27:50 -05:00
foreignKeys: [
2024-02-08 16:29:16 -05:00
{
fields: ['to', 'toName'],
references: () => [BaseUser.fields.id, BaseUser.fields.name],
},
2024-02-06 17:27:50 -05:00
],
2024-02-08 16:29:16 -05:00
}),
});
2024-02-06 17:27:50 -05:00
const expected = (tempTableName) => [
2024-02-08 16:29:16 -05:00
`CREATE TABLE \"${tempTableName}\" (_id INTEGER PRIMARY KEY, \"to\" integer NOT NULL, \"toName\" text NOT NULL, \"subject\" text NOT NULL, \"body\" text NOT NULL, FOREIGN KEY (\"to\", \"toName\") REFERENCES \"User\"(\"id\", \"name\"))`,
2024-02-06 17:27:50 -05:00
`INSERT INTO \"${tempTableName}\" (\"_id\", \"to\", \"toName\", \"subject\", \"body\") SELECT \"_id\", \"to\", \"toName\", \"subject\", \"body\" FROM \"User\"`,
'DROP TABLE "User"',
`ALTER TABLE \"${tempTableName}\" RENAME TO \"User\"`,
];
2024-02-08 16:29:16 -05:00
const addedForeignKey = await userChangeQueries(InitialWithoutFK, Final);
const updatedForeignKey = await userChangeQueries(InitialWithDifferentFK, Final);
2024-02-06 17:27:50 -05:00
expect(addedForeignKey.queries[0]).to.not.be.undefined;
expect(updatedForeignKey.queries[0]).to.not.be.undefined;
expect(addedForeignKey.queries).to.deep.equal(
expected(getTempTableName(addedForeignKey.queries[0]))
);
expect(updatedForeignKey.queries).to.deep.equal(
expected(getTempTableName(updatedForeignKey.queries[0]))
);
});
});
2024-02-08 16:29:16 -05:00
/** @param {string | undefined} query */
function getTempTableName(query) {
return query.match(/User_([a-z0-9]+)/)?.[0];
}