mirror of
https://github.com/withastro/astro.git
synced 2025-04-07 23:41:43 -05:00
Improved error logging from config (#10207)
* fix: better error messaging on seed() * chore: collection -> table for errors * chore: changeset
This commit is contained in:
parent
eb8bffe67a
commit
5d4ff093a2
4 changed files with 67 additions and 36 deletions
5
.changeset/young-pears-brake.md
Normal file
5
.changeset/young-pears-brake.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@astrojs/db": patch
|
||||
---
|
||||
|
||||
Improve error messaging when seeding invalid data.
|
|
@ -10,8 +10,8 @@ export const MISSING_PROJECT_ID_ERROR = `${red('▶ Directory not linked.')}
|
|||
To link this directory to an Astro Studio project, run
|
||||
${cyan('astro db link')}\n`;
|
||||
|
||||
export const STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR = (collectionName: string) => `${red(
|
||||
`▶ Writable collection ${bold(collectionName)} requires Astro Studio or the ${yellow(
|
||||
export const STUDIO_CONFIG_MISSING_WRITABLE_TABLE_ERROR = (tableName: string) => `${red(
|
||||
`▶ Writable table ${bold(tableName)} requires Astro Studio or the ${yellow(
|
||||
'unsafeWritable'
|
||||
)} option.`
|
||||
)}
|
||||
|
@ -34,10 +34,20 @@ export const MIGRATIONS_NOT_INITIALIZED = `${yellow(
|
|||
'▶ No migrations found!'
|
||||
)}\n\n To scaffold your migrations folder, run\n ${cyan('astro db sync')}\n`;
|
||||
|
||||
export const SEED_WRITABLE_IN_PROD_ERROR = (collectionName: string) => {
|
||||
export const SEED_WRITABLE_IN_PROD_ERROR = (tableName: string) => {
|
||||
return `${red(
|
||||
`Writable tables should not be seeded in production with data().`
|
||||
)} You can seed ${bold(
|
||||
collectionName
|
||||
tableName
|
||||
)} in development mode only using the "mode" flag. See the docs for more: https://www.notion.so/astroinc/astrojs-db-README-dcf6fa10de9a4f528be56cee96e8c054?pvs=4#278aed3fc37e4cec80240d1552ff6ac5`;
|
||||
};
|
||||
|
||||
export const SEED_ERROR = (tableName: string, error: string) => {
|
||||
return `${red(`Error seeding table ${bold(tableName)}:`)}\n\n${error}`;
|
||||
};
|
||||
|
||||
export const SEED_EMPTY_ARRAY_ERROR = (tableName: string) => {
|
||||
// Drizzle error says "values() must be called with at least one value."
|
||||
// This is specific to db.insert(). Prettify for seed().
|
||||
return SEED_ERROR(tableName, `Empty array was passed. seed() must receive at least one value.`);
|
||||
};
|
||||
|
|
|
@ -8,10 +8,7 @@ import { DB_PATH } from '../consts.js';
|
|||
import { createLocalDatabaseClient } from '../../runtime/db-client.js';
|
||||
import { astroConfigWithDbSchema, type DBTables } from '../types.js';
|
||||
import { type VitePlugin } from '../utils.js';
|
||||
import {
|
||||
STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR,
|
||||
UNSAFE_WRITABLE_WARNING,
|
||||
} from '../errors.js';
|
||||
import { STUDIO_CONFIG_MISSING_WRITABLE_TABLE_ERROR, UNSAFE_WRITABLE_WARNING } from '../errors.js';
|
||||
import { errorMap } from './error-map.js';
|
||||
import { dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
@ -76,9 +73,7 @@ function astroDBIntegration(): AstroIntegration {
|
|||
const foundWritableCollection = Object.entries(tables).find(([, c]) => c.writable);
|
||||
const writableAllowed = studio || unsafeWritable;
|
||||
if (!writableAllowed && foundWritableCollection) {
|
||||
logger.error(
|
||||
STUDIO_CONFIG_MISSING_WRITABLE_COLLECTIONS_ERROR(foundWritableCollection[0])
|
||||
);
|
||||
logger.error(STUDIO_CONFIG_MISSING_WRITABLE_TABLE_ERROR(foundWritableCollection[0]));
|
||||
process.exit(1);
|
||||
}
|
||||
// Using writable tables with the opt-in flag. Warn them to let them
|
||||
|
|
|
@ -14,10 +14,15 @@ import { bold } from 'kleur/colors';
|
|||
import { type SQL, sql, getTableName } from 'drizzle-orm';
|
||||
import { SQLiteAsyncDialect, type SQLiteInsert } from 'drizzle-orm/sqlite-core';
|
||||
import type { AstroIntegrationLogger } from 'astro';
|
||||
import type { DBUserConfig } from '../core/types.js';
|
||||
import type {
|
||||
ColumnsConfig,
|
||||
DBUserConfig,
|
||||
MaybeArray,
|
||||
ResolvedCollectionConfig,
|
||||
} from '../core/types.js';
|
||||
import { hasPrimaryKey } from '../runtime/index.js';
|
||||
import { isSerializedSQL } from '../runtime/types.js';
|
||||
import { SEED_WRITABLE_IN_PROD_ERROR } from './errors.js';
|
||||
import { SEED_EMPTY_ARRAY_ERROR, SEED_ERROR, SEED_WRITABLE_IN_PROD_ERROR } from './errors.js';
|
||||
|
||||
const sqlite = new SQLiteAsyncDialect();
|
||||
|
||||
|
@ -51,40 +56,56 @@ export async function seedData({
|
|||
logger?: AstroIntegrationLogger;
|
||||
mode: 'dev' | 'build';
|
||||
}) {
|
||||
const dataFns = Array.isArray(data) ? data : [data];
|
||||
try {
|
||||
const dataFns = Array.isArray(data) ? data : [data];
|
||||
for (const dataFn of dataFns) {
|
||||
await dataFn({
|
||||
seed: async ({ table, writable }, values) => {
|
||||
if (writable && mode === 'build' && process.env.ASTRO_DB_TEST_ENV !== '1') {
|
||||
(logger ?? console).error(SEED_WRITABLE_IN_PROD_ERROR(getTableName(table)));
|
||||
process.exit(1);
|
||||
seed: async (config, values) => {
|
||||
seedErrorChecks(mode, config, values);
|
||||
try {
|
||||
await db.insert(config.table).values(values as any);
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
throw new Error(SEED_ERROR(getTableName(config.table), msg));
|
||||
}
|
||||
await db.insert(table).values(values as any);
|
||||
},
|
||||
seedReturning: async ({ table, writable }, values) => {
|
||||
if (writable && mode === 'build' && process.env.ASTRO_DB_TEST_ENV !== '1') {
|
||||
(logger ?? console).error(SEED_WRITABLE_IN_PROD_ERROR(getTableName(table)));
|
||||
process.exit(1);
|
||||
seedReturning: async (config, values) => {
|
||||
seedErrorChecks(mode, config, values);
|
||||
try {
|
||||
let result: SQLiteInsert<any, any, any, any> = db
|
||||
.insert(config.table)
|
||||
.values(values as any)
|
||||
.returning();
|
||||
if (!Array.isArray(values)) {
|
||||
result = result.get();
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
throw new Error(SEED_ERROR(getTableName(config.table), msg));
|
||||
}
|
||||
let result: SQLiteInsert<any, any, any, any> = db
|
||||
.insert(table)
|
||||
.values(values as any)
|
||||
.returning();
|
||||
if (!Array.isArray(values)) {
|
||||
result = result.get();
|
||||
}
|
||||
return result;
|
||||
},
|
||||
db,
|
||||
mode,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
(logger ?? console).error(
|
||||
`Failed to seed data. Did you update to match recent schema changes?`
|
||||
);
|
||||
(logger ?? console).error(error as string);
|
||||
} catch (e) {
|
||||
if (!(e instanceof Error)) throw e;
|
||||
(logger ?? console).error(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function seedErrorChecks<T extends ColumnsConfig>(
|
||||
mode: 'dev' | 'build',
|
||||
{ table, writable }: ResolvedCollectionConfig<T, boolean>,
|
||||
values: MaybeArray<unknown>
|
||||
) {
|
||||
const tableName = getTableName(table);
|
||||
if (writable && mode === 'build' && process.env.ASTRO_DB_TEST_ENV !== '1') {
|
||||
throw new Error(SEED_WRITABLE_IN_PROD_ERROR(tableName));
|
||||
}
|
||||
if (Array.isArray(values) && values.length === 0) {
|
||||
throw new Error(SEED_EMPTY_ARRAY_ERROR(tableName));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue