mirror of
https://github.com/withastro/astro.git
synced 2025-02-10 22:38:53 -05:00
refactor: move dev to use filesystem to run seed at right time
This commit is contained in:
parent
6ad4e00cd0
commit
4e941af5fb
3 changed files with 38 additions and 73 deletions
|
@ -3,29 +3,29 @@ import { vitePluginDb } from './vite-plugin-db.js';
|
||||||
import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js';
|
import { vitePluginInjectEnvTs } from './vite-plugin-inject-env-ts.js';
|
||||||
import { typegen } from './typegen.js';
|
import { typegen } from './typegen.js';
|
||||||
import { collectionsSchema } from './types.js';
|
import { collectionsSchema } from './types.js';
|
||||||
import { seed } from './seed.js';
|
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { rm } from 'fs/promises';
|
import { rm } from 'fs/promises';
|
||||||
import { getDbUrl } from './consts.js';
|
import { getDbUrl } from './consts.js';
|
||||||
|
import { createDb, setupDbTables } from './internal.js';
|
||||||
|
|
||||||
export function integration(): AstroIntegration {
|
export function integration(): AstroIntegration {
|
||||||
return {
|
return {
|
||||||
name: 'astro:db',
|
name: 'astro:db',
|
||||||
hooks: {
|
hooks: {
|
||||||
async 'astro:config:setup'({ updateConfig, config, command }) {
|
async 'astro:config:setup'({ logger, updateConfig, config, command }) {
|
||||||
if (command === 'preview') return;
|
if (command === 'preview') return;
|
||||||
|
|
||||||
// TODO: refine where we load collections
|
// TODO: refine where we load collections
|
||||||
// @matthewp: may want to load collections by path at runtime
|
// @matthewp: may want to load collections by path at runtime
|
||||||
const collections = collectionsSchema.parse(config.db?.collections ?? {});
|
const collections = collectionsSchema.parse(config.db?.collections ?? {});
|
||||||
const isDev = command === 'dev';
|
const dbUrl = getDbUrl(config.root);
|
||||||
if (command === 'build') {
|
if (existsSync(dbUrl)) {
|
||||||
const dbUrl = getDbUrl(config.root);
|
await rm(dbUrl);
|
||||||
if (existsSync(dbUrl)) {
|
|
||||||
await rm(dbUrl);
|
|
||||||
}
|
|
||||||
await seed({ collections, root: config.root });
|
|
||||||
}
|
}
|
||||||
|
const db = await createDb({ dbUrl: dbUrl.href });
|
||||||
|
await setupDbTables({ db, collections, logger });
|
||||||
|
logger.info('Collections set up 🚀');
|
||||||
|
|
||||||
updateConfig({
|
updateConfig({
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -34,7 +34,6 @@ export function integration(): AstroIntegration {
|
||||||
vitePluginDb({
|
vitePluginDb({
|
||||||
collections,
|
collections,
|
||||||
root: config.root,
|
root: config.root,
|
||||||
isDev,
|
|
||||||
}),
|
}),
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
vitePluginInjectEnvTs(config),
|
vitePluginInjectEnvTs(config),
|
||||||
|
|
|
@ -24,6 +24,7 @@ import {
|
||||||
} from 'drizzle-orm/sqlite-core';
|
} from 'drizzle-orm/sqlite-core';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
|
import type { AstroIntegrationLogger } from 'astro';
|
||||||
|
|
||||||
export type SqliteDB = SqliteRemoteDatabase;
|
export type SqliteDB = SqliteRemoteDatabase;
|
||||||
export type {
|
export type {
|
||||||
|
@ -38,25 +39,21 @@ export type {
|
||||||
|
|
||||||
const sqlite = new SQLiteAsyncDialect();
|
const sqlite = new SQLiteAsyncDialect();
|
||||||
|
|
||||||
export async function createDb({
|
export async function createDb({ dbUrl }: { dbUrl: string }) {
|
||||||
collections,
|
|
||||||
dbUrl,
|
|
||||||
createTables = false,
|
|
||||||
}: {
|
|
||||||
collections: DBCollections;
|
|
||||||
dbUrl: string;
|
|
||||||
createTables?: boolean;
|
|
||||||
}) {
|
|
||||||
const client = createClient({ url: dbUrl });
|
const client = createClient({ url: dbUrl });
|
||||||
const db = drizzle(client);
|
const db = drizzle(client);
|
||||||
|
|
||||||
if (createTables) {
|
|
||||||
await createDbTables(db, collections);
|
|
||||||
}
|
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createDbTables(db: LibSQLDatabase, collections: DBCollections) {
|
export async function setupDbTables({
|
||||||
|
db,
|
||||||
|
collections,
|
||||||
|
logger,
|
||||||
|
}: {
|
||||||
|
db: LibSQLDatabase;
|
||||||
|
collections: DBCollections;
|
||||||
|
logger: AstroIntegrationLogger;
|
||||||
|
}) {
|
||||||
const setupQueries: SQL[] = [];
|
const setupQueries: SQL[] = [];
|
||||||
for (const [name, collection] of Object.entries(collections)) {
|
for (const [name, collection] of Object.entries(collections)) {
|
||||||
const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${name}`);
|
const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${name}`);
|
||||||
|
@ -66,6 +63,20 @@ async function createDbTables(db: LibSQLDatabase, collections: DBCollections) {
|
||||||
for (const q of setupQueries) {
|
for (const q of setupQueries) {
|
||||||
await db.run(q);
|
await db.run(q);
|
||||||
}
|
}
|
||||||
|
for (const [name, collection] of Object.entries(collections)) {
|
||||||
|
if (!collection.data) continue;
|
||||||
|
|
||||||
|
const table = collectionToTable(name, collection);
|
||||||
|
try {
|
||||||
|
await db.insert(table).values(await collection.data());
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(
|
||||||
|
`Failed to seed ${bold(
|
||||||
|
name
|
||||||
|
)} data. Did you update to match recent schema changes? Full error:\n\n${e}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCreateTableQuery(collectionName: string, collection: DBCollection) {
|
export function getCreateTableQuery(collectionName: string, collection: DBCollection) {
|
||||||
|
@ -83,22 +94,6 @@ export function getCreateTableQuery(collectionName: string, collection: DBCollec
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function executeCollectionDataFn({
|
|
||||||
db,
|
|
||||||
collectionName,
|
|
||||||
collection,
|
|
||||||
}: {
|
|
||||||
db: LibSQLDatabase;
|
|
||||||
collectionName: string;
|
|
||||||
collection: DBCollection;
|
|
||||||
}) {
|
|
||||||
const { data } = collection;
|
|
||||||
if (!data) return;
|
|
||||||
|
|
||||||
const table = collectionToTable(collectionName, collection);
|
|
||||||
await db.insert(table).values(await data());
|
|
||||||
}
|
|
||||||
|
|
||||||
function schemaTypeToSqlType(type: FieldType): 'text' | 'integer' {
|
function schemaTypeToSqlType(type: FieldType): 'text' | 'integer' {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'date':
|
case 'date':
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
import { existsSync } from 'node:fs';
|
import { existsSync } from 'node:fs';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { DRIZZLE_MOD_IMPORT, INTERNAL_MOD_IMPORT, VIRTUAL_MODULE_ID, getDbUrl } from './consts.js';
|
||||||
import { red } from 'kleur/colors';
|
|
||||||
import {
|
|
||||||
DRIZZLE_MOD_IMPORT,
|
|
||||||
INTERNAL_MOD_IMPORT,
|
|
||||||
SUPPORTED_SEED_FILES,
|
|
||||||
VIRTUAL_MODULE_ID,
|
|
||||||
getDbUrl,
|
|
||||||
} from './consts.js';
|
|
||||||
import type { DBCollections } from './types.js';
|
import type { DBCollections } from './types.js';
|
||||||
import type { Plugin as VitePlugin } from 'vite';
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
|
|
||||||
|
@ -16,11 +8,9 @@ const resolvedVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
||||||
export function vitePluginDb({
|
export function vitePluginDb({
|
||||||
collections,
|
collections,
|
||||||
root,
|
root,
|
||||||
isDev,
|
|
||||||
}: {
|
}: {
|
||||||
collections: DBCollections;
|
collections: DBCollections;
|
||||||
root: URL;
|
root: URL;
|
||||||
isDev: boolean;
|
|
||||||
}): VitePlugin {
|
}): VitePlugin {
|
||||||
return {
|
return {
|
||||||
name: 'astro:db',
|
name: 'astro:db',
|
||||||
|
@ -32,29 +22,20 @@ export function vitePluginDb({
|
||||||
},
|
},
|
||||||
load(id) {
|
load(id) {
|
||||||
if (id !== resolvedVirtualModuleId) return;
|
if (id !== resolvedVirtualModuleId) return;
|
||||||
return getVirtualModContents({ collections, root, isDev });
|
return getVirtualModContents({ collections, root });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const seedErrorMessage = `${red(
|
|
||||||
'⚠️ Failed to seed data.'
|
|
||||||
)} Is the seed file out-of-date with recent schema changes?`;
|
|
||||||
|
|
||||||
export function getVirtualModContents({
|
export function getVirtualModContents({
|
||||||
collections,
|
collections,
|
||||||
root,
|
root,
|
||||||
isDev,
|
|
||||||
}: {
|
}: {
|
||||||
collections: DBCollections;
|
collections: DBCollections;
|
||||||
root: URL;
|
root: URL;
|
||||||
isDev: boolean;
|
|
||||||
}) {
|
}) {
|
||||||
const seedFile = SUPPORTED_SEED_FILES.map((f) => fileURLToPath(new URL(f, root))).find((f) =>
|
const dbUrl = getDbUrl(root).href;
|
||||||
existsSync(f)
|
const shouldSetUpDb = !existsSync(getDbUrl(root));
|
||||||
);
|
|
||||||
const dbUrl = isDev ? ':memory:' : getDbUrl(root).href;
|
|
||||||
const shouldSetUpDb = isDev || !existsSync(getDbUrl(root));
|
|
||||||
return `
|
return `
|
||||||
import { collectionToTable, createDb } from ${INTERNAL_MOD_IMPORT};
|
import { collectionToTable, createDb } from ${INTERNAL_MOD_IMPORT};
|
||||||
|
|
||||||
|
@ -66,16 +47,6 @@ export const db = await createDb(${JSON.stringify({
|
||||||
export * from ${DRIZZLE_MOD_IMPORT};
|
export * from ${DRIZZLE_MOD_IMPORT};
|
||||||
|
|
||||||
${getStringifiedCollectionExports(collections)}
|
${getStringifiedCollectionExports(collections)}
|
||||||
|
|
||||||
${
|
|
||||||
seedFile && isDev
|
|
||||||
? `try {
|
|
||||||
await import(${JSON.stringify(seedFile)});
|
|
||||||
} catch {
|
|
||||||
console.error(${JSON.stringify(seedErrorMessage)});
|
|
||||||
}`
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue