mirror of
https://github.com/withastro/astro.git
synced 2025-02-03 22:29:08 -05:00
feat: index migrations
This commit is contained in:
parent
8f342b0db7
commit
84e5bd0830
3 changed files with 77 additions and 23 deletions
|
@ -1,4 +1,5 @@
|
|||
import * as color from 'kleur/colors';
|
||||
import deepDiff from 'deep-diff';
|
||||
import type {
|
||||
BooleanField,
|
||||
DBCollection,
|
||||
|
@ -8,6 +9,7 @@ import type {
|
|||
DBSnapshot,
|
||||
DateField,
|
||||
FieldType,
|
||||
Indexes,
|
||||
JsonField,
|
||||
NumberField,
|
||||
TextField,
|
||||
|
@ -18,6 +20,7 @@ import prompts from 'prompts';
|
|||
import {
|
||||
getCreateTableQuery,
|
||||
getModifiers,
|
||||
getCreateIndexQueries,
|
||||
hasDefault,
|
||||
hasPrimaryKey,
|
||||
schemaTypeToSqlType,
|
||||
|
@ -62,6 +65,7 @@ export async function getMigrationQueries({
|
|||
|
||||
for (const [collectionName, collection] of Object.entries(added)) {
|
||||
queries.push(getCreateTableQuery(collectionName, collection));
|
||||
queries.push(...getCreateIndexQueries(collectionName, collection));
|
||||
}
|
||||
|
||||
for (const [collectionName] of Object.entries(dropped)) {
|
||||
|
@ -96,11 +100,15 @@ export async function getCollectionChangeQueries({
|
|||
}): Promise<string[]> {
|
||||
const queries: string[] = [];
|
||||
const updated = getUpdatedFields(oldCollection.fields, newCollection.fields);
|
||||
let added = getAddedFields(oldCollection.fields, newCollection.fields);
|
||||
let dropped = getDroppedFields(oldCollection.fields, newCollection.fields);
|
||||
let added = getAdded(oldCollection.fields, newCollection.fields);
|
||||
let dropped = getDropped(oldCollection.fields, newCollection.fields);
|
||||
|
||||
if (isEmpty(updated) && isEmpty(added) && isEmpty(dropped)) {
|
||||
return [];
|
||||
return getChangeIndexQueries({
|
||||
collectionName,
|
||||
oldIndexes: oldCollection.indexes,
|
||||
newIndexes: newCollection.indexes,
|
||||
});
|
||||
}
|
||||
if (!isEmpty(added) && !isEmpty(dropped)) {
|
||||
const resolved = await resolveFieldRenames(
|
||||
|
@ -118,7 +126,14 @@ export async function getCollectionChangeQueries({
|
|||
Object.values(dropped).every(canAlterTableDropColumn) &&
|
||||
Object.values(added).every(canAlterTableAddColumn)
|
||||
) {
|
||||
queries.push(...getAlterTableQueries(collectionName, added, dropped));
|
||||
queries.push(
|
||||
...getAlterTableQueries(collectionName, added, dropped),
|
||||
...getChangeIndexQueries({
|
||||
collectionName,
|
||||
oldIndexes: oldCollection.indexes,
|
||||
newIndexes: newCollection.indexes,
|
||||
})
|
||||
);
|
||||
return queries;
|
||||
}
|
||||
|
||||
|
@ -158,7 +173,7 @@ export async function getCollectionChangeQueries({
|
|||
allowDataLoss = !!res.allowDataLoss;
|
||||
}
|
||||
if (!allowDataLoss) {
|
||||
console.log('Exiting without changes 👋');
|
||||
console.info('Exiting without changes 👋');
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +190,32 @@ export async function getCollectionChangeQueries({
|
|||
hasDataLoss: dataLossCheck.dataLoss,
|
||||
migrateHiddenPrimaryKey: !addedPrimaryKey && !droppedPrimaryKey && !updatedPrimaryKey,
|
||||
});
|
||||
queries.push(...recreateTableQueries);
|
||||
queries.push(...recreateTableQueries, ...getCreateIndexQueries(collectionName, newCollection));
|
||||
return queries;
|
||||
}
|
||||
|
||||
function getChangeIndexQueries({
|
||||
collectionName,
|
||||
oldIndexes = {},
|
||||
newIndexes = {},
|
||||
}: {
|
||||
collectionName: string;
|
||||
oldIndexes?: Indexes;
|
||||
newIndexes?: Indexes;
|
||||
}) {
|
||||
const added = getAdded(oldIndexes, newIndexes);
|
||||
const dropped = getDropped(oldIndexes, newIndexes);
|
||||
const updated = getUpdated(oldIndexes, newIndexes);
|
||||
|
||||
Object.assign(dropped, updated);
|
||||
Object.assign(added, updated);
|
||||
|
||||
const queries: string[] = [];
|
||||
for (const indexName of Object.keys(dropped)) {
|
||||
const dropQuery = `DROP INDEX ${sqlite.escapeName(indexName)}`;
|
||||
queries.push(dropQuery);
|
||||
}
|
||||
queries.push(...getCreateIndexQueries(collectionName, { indexes: added }));
|
||||
return queries;
|
||||
}
|
||||
|
||||
|
@ -454,22 +494,32 @@ function canRecreateTableWithoutDataLoss(
|
|||
return { dataLoss: false };
|
||||
}
|
||||
|
||||
function getAddedFields(oldFields: DBFields, newFields: DBFields) {
|
||||
const added: DBFields = {};
|
||||
for (const [key, newField] of Object.entries(newFields)) {
|
||||
if (!(key in oldFields)) added[key] = newField;
|
||||
function getAdded<T>(oldObj: Record<string, T>, newObj: Record<string, T>) {
|
||||
const added: Record<string, T> = {};
|
||||
for (const [key, value] of Object.entries(newObj)) {
|
||||
if (!(key in oldObj)) added[key] = value;
|
||||
}
|
||||
return added;
|
||||
}
|
||||
|
||||
function getDroppedFields(oldFields: DBFields, newFields: DBFields) {
|
||||
const dropped: DBFields = {};
|
||||
for (const [key, oldField] of Object.entries(oldFields)) {
|
||||
if (!(key in newFields)) dropped[key] = oldField;
|
||||
function getDropped<T>(oldObj: Record<string, T>, newObj: Record<string, T>) {
|
||||
const dropped: Record<string, T> = {};
|
||||
for (const [key, value] of Object.entries(oldObj)) {
|
||||
if (!(key in newObj)) dropped[key] = value;
|
||||
}
|
||||
return dropped;
|
||||
}
|
||||
|
||||
function getUpdated<T>(oldObj: Record<string, T>, newObj: Record<string, T>) {
|
||||
const updated: Record<string, T> = {};
|
||||
for (const [key, value] of Object.entries(newObj)) {
|
||||
const oldValue = oldObj[key];
|
||||
if (!oldValue) continue;
|
||||
if (deepDiff(oldValue, value)) updated[key] = value;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
type UpdatedFields = Record<string, { old: DBField; new: DBField }>;
|
||||
|
||||
function getUpdatedFields(oldFields: DBFields, newFields: DBFields): UpdatedFields {
|
||||
|
@ -479,6 +529,7 @@ function getUpdatedFields(oldFields: DBFields, newFields: DBFields): UpdatedFiel
|
|||
if (!oldField) continue;
|
||||
if (objShallowEqual(oldField, newField)) continue;
|
||||
|
||||
// TODO: refactor to deep-diff with a prefilter on `type`
|
||||
const oldFieldSqlType = { ...oldField, type: schemaTypeToSqlType(oldField.type) };
|
||||
const newFieldSqlType = { ...newField, type: schemaTypeToSqlType(newField.type) };
|
||||
const isSafeTypeUpdate =
|
||||
|
|
|
@ -101,8 +101,8 @@ export async function setupDbTables({
|
|||
for (const [name, collection] of Object.entries(collections)) {
|
||||
const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${name}`);
|
||||
const createQuery = sql.raw(getCreateTableQuery(name, collection));
|
||||
const indexQueries = getTableIndexQueries(name, collection);
|
||||
setupQueries.push(dropQuery, createQuery, ...indexQueries);
|
||||
const indexQueries = getCreateIndexQueries(name, collection);
|
||||
setupQueries.push(dropQuery, createQuery, ...indexQueries.map((s) => sql.raw(s)));
|
||||
}
|
||||
for (const q of setupQueries) {
|
||||
await db.run(q);
|
||||
|
@ -160,18 +160,19 @@ export function getCreateTableQuery(collectionName: string, collection: DBCollec
|
|||
return query;
|
||||
}
|
||||
|
||||
export function getTableIndexQueries(collectionName: string, collection: DBCollection) {
|
||||
let queries: SQL[] = [];
|
||||
export function getCreateIndexQueries(
|
||||
collectionName: string,
|
||||
collection: Pick<DBCollection, 'indexes'>
|
||||
) {
|
||||
let queries: string[] = [];
|
||||
for (const [indexName, indexProps] of Object.entries(collection.indexes ?? {})) {
|
||||
const onColNames = Array.isArray(indexProps.on) ? indexProps.on : [indexProps.on];
|
||||
const onCols = onColNames.map((colName) => sqlite.escapeName(colName));
|
||||
|
||||
const unique = indexProps.unique ? 'UNIQUE ' : '';
|
||||
const indexQuery = sql.raw(
|
||||
`CREATE ${unique}INDEX ${sqlite.escapeName(indexName)} ON ${sqlite.escapeName(
|
||||
collectionName
|
||||
)} (${onCols.join(', ')})`
|
||||
);
|
||||
const indexQuery = `CREATE ${unique}INDEX ${sqlite.escapeName(
|
||||
indexName
|
||||
)} ON ${sqlite.escapeName(collectionName)} (${onCols.join(', ')})`;
|
||||
queries.push(indexQuery);
|
||||
}
|
||||
return queries;
|
||||
|
|
|
@ -58,6 +58,8 @@ export const indexSchema = z.object({
|
|||
});
|
||||
const indexesSchema = z.record(indexSchema);
|
||||
|
||||
export type Indexes = z.infer<typeof indexesSchema>;
|
||||
|
||||
const baseCollectionSchema = z.object({
|
||||
fields: fieldsSchema,
|
||||
indexes: indexesSchema.optional(),
|
||||
|
|
Loading…
Add table
Reference in a new issue