0
Fork 0
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:
Ben Holmes 2024-02-23 17:01:33 -05:00 committed by GitHub
parent eb8bffe67a
commit 5d4ff093a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 67 additions and 36 deletions

View file

@ -0,0 +1,5 @@
---
"@astrojs/db": patch
---
Improve error messaging when seeding invalid data.

View file

@ -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.`);
};

View file

@ -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

View file

@ -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));
}
}