@astrojs/db 0.6.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,13 @@
1
1
  import { existsSync } from "node:fs";
2
- import { FILE_NOT_FOUND_ERROR, MISSING_EXECUTE_PATH_ERROR } from "../../../errors.js";
3
- import { getStudioVirtualModContents } from "../../../integration/vite-plugin-db.js";
2
+ import {
3
+ FILE_NOT_FOUND_ERROR,
4
+ MISSING_EXECUTE_PATH_ERROR,
5
+ SEED_DEFAULT_EXPORT_ERROR
6
+ } from "../../../errors.js";
7
+ import {
8
+ getLocalVirtualModContents,
9
+ getStudioVirtualModContents
10
+ } from "../../../integration/vite-plugin-db.js";
4
11
  import { bundleFile, importBundledFile } from "../../../load-file.js";
5
12
  import { getManagedAppTokenOrExit } from "../../../tokens.js";
6
13
  import {} from "../../../types.js";
@@ -19,13 +26,28 @@ async function cmd({
19
26
  console.error(FILE_NOT_FOUND_ERROR(filePath));
20
27
  process.exit(1);
21
28
  }
22
- const appToken = await getManagedAppTokenOrExit(flags.token);
23
- const virtualModContents = getStudioVirtualModContents({
24
- tables: dbConfig.tables ?? {},
25
- appToken: appToken.token
26
- });
29
+ let virtualModContents;
30
+ if (flags.remote) {
31
+ const appToken = await getManagedAppTokenOrExit(flags.token);
32
+ virtualModContents = getStudioVirtualModContents({
33
+ tables: dbConfig.tables ?? {},
34
+ appToken: appToken.token
35
+ });
36
+ } else {
37
+ virtualModContents = getLocalVirtualModContents({
38
+ tables: dbConfig.tables ?? {},
39
+ root: astroConfig.root,
40
+ shouldSeed: false,
41
+ seedFiles: []
42
+ });
43
+ }
27
44
  const { code } = await bundleFile({ virtualModContents, root: astroConfig.root, fileUrl });
28
- await importBundledFile({ code, root: astroConfig.root });
45
+ const mod = await importBundledFile({ code, root: astroConfig.root });
46
+ if (typeof mod.default !== "function") {
47
+ console.error(SEED_DEFAULT_EXPORT_ERROR);
48
+ process.exit(1);
49
+ }
50
+ await mod.default();
29
51
  }
30
52
  export {
31
53
  cmd
@@ -1,4 +1,4 @@
1
- import { red } from "kleur/colors";
1
+ import { MIGRATION_VERSION } from "../../../consts.js";
2
2
  import { getManagedAppTokenOrExit } from "../../../tokens.js";
3
3
  import {} from "../../../types.js";
4
4
  import { getRemoteDatabaseUrl } from "../../../utils.js";
@@ -57,7 +57,7 @@ async function pushSchema({
57
57
  const requestBody = {
58
58
  snapshot: currentSnapshot,
59
59
  sql: statements,
60
- experimentalVersion: 1
60
+ version: MIGRATION_VERSION
61
61
  };
62
62
  if (isDryRun) {
63
63
  console.info("[DRY RUN] Batch query:", JSON.stringify(requestBody, null, 2));
@@ -1,7 +1,7 @@
1
1
  import type { AstroConfig } from 'astro';
2
2
  import type { Arguments } from 'yargs-parser';
3
3
  import type { DBConfigInput } from '../../../types.js';
4
- export declare function cmd({ flags, }: {
4
+ export declare function cmd({ flags, astroConfig, }: {
5
5
  dbConfig: DBConfigInput;
6
6
  astroConfig: AstroConfig;
7
7
  flags: Arguments;
@@ -1,16 +1,32 @@
1
1
  import { sql } from "drizzle-orm";
2
- import { createRemoteDatabaseClient } from "../../../../runtime/db-client.js";
2
+ import {
3
+ createLocalDatabaseClient,
4
+ createRemoteDatabaseClient
5
+ } from "../../../../runtime/db-client.js";
6
+ import { DB_PATH } from "../../../consts.js";
7
+ import { SHELL_QUERY_MISSING_ERROR } from "../../../errors.js";
3
8
  import { getManagedAppTokenOrExit } from "../../../tokens.js";
4
9
  import { getRemoteDatabaseUrl } from "../../../utils.js";
5
10
  async function cmd({
6
- flags
11
+ flags,
12
+ astroConfig
7
13
  }) {
8
14
  const query = flags.query;
9
- const appToken = await getManagedAppTokenOrExit(flags.token);
10
- const db = createRemoteDatabaseClient(appToken.token, getRemoteDatabaseUrl());
11
- const result = await db.run(sql.raw(query));
12
- await appToken.destroy();
13
- console.log(result);
15
+ if (!query) {
16
+ console.error(SHELL_QUERY_MISSING_ERROR);
17
+ process.exit(1);
18
+ }
19
+ if (flags.remote) {
20
+ const appToken = await getManagedAppTokenOrExit(flags.token);
21
+ const db = createRemoteDatabaseClient(appToken.token, getRemoteDatabaseUrl());
22
+ const result = await db.run(sql.raw(query));
23
+ await appToken.destroy();
24
+ console.log(result);
25
+ } else {
26
+ const db = createLocalDatabaseClient({ dbUrl: new URL(DB_PATH, astroConfig.root).href });
27
+ const result = await db.run(sql.raw(query));
28
+ console.log(result);
29
+ }
14
30
  }
15
31
  export {
16
32
  cmd
@@ -1,13 +1,11 @@
1
- import { loadDbConfigFile } from "../load-file.js";
2
- import { dbConfigSchema } from "../types.js";
1
+ import { resolveDbConfig } from "../load-file.js";
3
2
  async function cli({
4
3
  flags,
5
4
  config: astroConfig
6
5
  }) {
7
6
  const args = flags._;
8
7
  const command = args[2] === "db" ? args[3] : args[2];
9
- const { mod } = await loadDbConfigFile(astroConfig.root);
10
- const dbConfig = dbConfigSchema.parse(mod?.default ?? {});
8
+ const { dbConfig } = await resolveDbConfig(astroConfig);
11
9
  switch (command) {
12
10
  case "shell": {
13
11
  const { cmd } = await import("./commands/shell/index.js");
@@ -14,6 +14,7 @@ import {
14
14
  schemaTypeToSqlType
15
15
  } from "../../runtime/queries.js";
16
16
  import { isSerializedSQL } from "../../runtime/types.js";
17
+ import { MIGRATION_VERSION } from "../consts.js";
17
18
  import { RENAME_COLUMN_ERROR, RENAME_TABLE_ERROR } from "../errors.js";
18
19
  import {
19
20
  columnSchema
@@ -335,10 +336,10 @@ async function getProductionCurrentSnapshot({
335
336
  }
336
337
  function createCurrentSnapshot({ tables = {} }) {
337
338
  const schema = JSON.parse(JSON.stringify(tables));
338
- return { experimentalVersion: 1, schema };
339
+ return { version: MIGRATION_VERSION, schema };
339
340
  }
340
341
  function createEmptySnapshot() {
341
- return { experimentalVersion: 1, schema: {} };
342
+ return { version: MIGRATION_VERSION, schema: {} };
342
343
  }
343
344
  function formatDataLossMessage(confirmations, isColor = true) {
344
345
  const messages = [];
@@ -1,8 +1,8 @@
1
1
  export declare const PACKAGE_NAME: any;
2
2
  export declare const RUNTIME_IMPORT: string;
3
- export declare const RUNTIME_DRIZZLE_IMPORT: string;
4
3
  export declare const RUNTIME_CONFIG_IMPORT: string;
5
4
  export declare const DB_TYPES_FILE = "db-types.d.ts";
6
5
  export declare const VIRTUAL_MODULE_ID = "astro:db";
7
- export declare const DB_PATH = ".astro/content.db";
6
+ export declare const DB_PATH: string;
8
7
  export declare const CONFIG_FILE_NAMES: string[];
8
+ export declare const MIGRATION_VERSION = "2024-03-12";
@@ -1,21 +1,22 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { readFileSync } from "node:fs";
2
3
  const PACKAGE_NAME = JSON.parse(
3
4
  readFileSync(new URL("../../package.json", import.meta.url), "utf8")
4
5
  ).name;
5
6
  const RUNTIME_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime`);
6
- const RUNTIME_DRIZZLE_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime/drizzle`);
7
7
  const RUNTIME_CONFIG_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime/config`);
8
8
  const DB_TYPES_FILE = "db-types.d.ts";
9
9
  const VIRTUAL_MODULE_ID = "astro:db";
10
- const DB_PATH = ".astro/content.db";
10
+ const DB_PATH = `.astro/${process.env.ASTRO_TEST_RANDOM_DB_ID ? randomUUID() : "content.db"}`;
11
11
  const CONFIG_FILE_NAMES = ["config.ts", "config.js", "config.mts", "config.mjs"];
12
+ const MIGRATION_VERSION = "2024-03-12";
12
13
  export {
13
14
  CONFIG_FILE_NAMES,
14
15
  DB_PATH,
15
16
  DB_TYPES_FILE,
17
+ MIGRATION_VERSION,
16
18
  PACKAGE_NAME,
17
19
  RUNTIME_CONFIG_IMPORT,
18
- RUNTIME_DRIZZLE_IMPORT,
19
20
  RUNTIME_IMPORT,
20
21
  VIRTUAL_MODULE_ID
21
22
  };
@@ -4,8 +4,11 @@ export declare const MISSING_EXECUTE_PATH_ERROR: string;
4
4
  export declare const RENAME_TABLE_ERROR: (oldTable: string, newTable: string) => string;
5
5
  export declare const RENAME_COLUMN_ERROR: (oldSelector: string, newSelector: string) => string;
6
6
  export declare const FILE_NOT_FOUND_ERROR: (path: string) => string;
7
+ export declare const SHELL_QUERY_MISSING_ERROR: string;
7
8
  export declare const SEED_ERROR: (error: string) => string;
9
+ export declare const SEED_DEFAULT_EXPORT_ERROR: (fileName: string) => string;
8
10
  export declare const REFERENCE_DNE_ERROR: (columnName: string) => string;
9
11
  export declare const FOREIGN_KEY_DNE_ERROR: (tableName: string) => string;
10
12
  export declare const FOREIGN_KEY_REFERENCES_LENGTH_ERROR: (tableName: string) => string;
11
13
  export declare const FOREIGN_KEY_REFERENCES_EMPTY_ERROR: (tableName: string) => string;
14
+ export declare const INTEGRATION_TABLE_CONFLICT_ERROR: (integrationName: string, tableName: string, isUserConflict: boolean) => string;
@@ -1,4 +1,4 @@
1
- import { bold, cyan, green, red, yellow } from "kleur/colors";
1
+ import { bold, cyan, red } from "kleur/colors";
2
2
  const MISSING_SESSION_ID_ERROR = `${red("\u25B6 Login required!")}
3
3
 
4
4
  To authenticate with Astro Studio, run
@@ -25,11 +25,20 @@ const RENAME_COLUMN_ERROR = (oldSelector, newSelector) => {
25
25
  };
26
26
  const FILE_NOT_FOUND_ERROR = (path) => `${red("\u25B6 File not found:")} ${bold(path)}
27
27
  `;
28
+ const SHELL_QUERY_MISSING_ERROR = `${red(
29
+ "\u25B6 Please provide a query to execute using the --query flag."
30
+ )}
31
+ `;
28
32
  const SEED_ERROR = (error) => {
29
33
  return `${red(`Error while seeding database:`)}
30
34
 
31
35
  ${error}`;
32
36
  };
37
+ const SEED_DEFAULT_EXPORT_ERROR = (fileName) => {
38
+ return red("Error while seeding database:") + `
39
+
40
+ Missing default function export in ${bold(fileName)}`;
41
+ };
33
42
  const REFERENCE_DNE_ERROR = (columnName) => {
34
43
  return `Column ${bold(
35
44
  columnName
@@ -50,16 +59,24 @@ const FOREIGN_KEY_REFERENCES_EMPTY_ERROR = (tableName) => {
50
59
  tableName
51
60
  )} is misconfigured. \`references\` array cannot be empty.`;
52
61
  };
62
+ const INTEGRATION_TABLE_CONFLICT_ERROR = (integrationName, tableName, isUserConflict) => {
63
+ return red("\u25B6 Conflicting table name in integration " + bold(integrationName)) + isUserConflict ? `
64
+ A user-defined table named ${bold(tableName)} already exists` : `
65
+ Another integration already added a table named ${bold(tableName)}`;
66
+ };
53
67
  export {
54
68
  FILE_NOT_FOUND_ERROR,
55
69
  FOREIGN_KEY_DNE_ERROR,
56
70
  FOREIGN_KEY_REFERENCES_EMPTY_ERROR,
57
71
  FOREIGN_KEY_REFERENCES_LENGTH_ERROR,
72
+ INTEGRATION_TABLE_CONFLICT_ERROR,
58
73
  MISSING_EXECUTE_PATH_ERROR,
59
74
  MISSING_PROJECT_ID_ERROR,
60
75
  MISSING_SESSION_ID_ERROR,
61
76
  REFERENCE_DNE_ERROR,
62
77
  RENAME_COLUMN_ERROR,
63
78
  RENAME_TABLE_ERROR,
64
- SEED_ERROR
79
+ SEED_DEFAULT_EXPORT_ERROR,
80
+ SEED_ERROR,
81
+ SHELL_QUERY_MISSING_ERROR
65
82
  };
@@ -3,12 +3,11 @@ import { dirname } from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  import { mkdir, rm, writeFile } from "fs/promises";
5
5
  import { blue, yellow } from "kleur/colors";
6
+ import parseArgs from "yargs-parser";
6
7
  import { CONFIG_FILE_NAMES, DB_PATH } from "../consts.js";
7
- import { loadDbConfigFile } from "../load-file.js";
8
+ import { resolveDbConfig } from "../load-file.js";
8
9
  import { getManagedAppTokenOrExit } from "../tokens.js";
9
- import { dbConfigSchema } from "../types.js";
10
10
  import { getDbDirectoryUrl } from "../utils.js";
11
- import { errorMap } from "./error-map.js";
12
11
  import { fileURLIntegration } from "./file-url.js";
13
12
  import { typegen } from "./typegen.js";
14
13
  import { vitePluginDb } from "./vite-plugin-db.js";
@@ -18,12 +17,16 @@ function astroDBIntegration() {
18
17
  let configFileDependencies = [];
19
18
  let root;
20
19
  let appToken;
21
- let dbConfig;
22
20
  let tables = {
23
21
  get() {
24
22
  throw new Error("[astro:db] INTERNAL Tables not loaded yet");
25
23
  }
26
24
  };
25
+ let seedFiles = {
26
+ get() {
27
+ throw new Error("[astro:db] INTERNAL Seed files not loaded yet");
28
+ }
29
+ };
27
30
  let command;
28
31
  return {
29
32
  name: "astro:db",
@@ -34,7 +37,8 @@ function astroDBIntegration() {
34
37
  if (command === "preview")
35
38
  return;
36
39
  let dbPlugin = void 0;
37
- connectToStudio = command === "build";
40
+ const args = parseArgs(process.argv.slice(3));
41
+ connectToStudio = args["remote"];
38
42
  if (connectToStudio) {
39
43
  appToken = await getManagedAppTokenOrExit();
40
44
  dbPlugin = vitePluginDb({
@@ -48,6 +52,7 @@ function astroDBIntegration() {
48
52
  dbPlugin = vitePluginDb({
49
53
  connectToStudio: false,
50
54
  tables,
55
+ seedFiles,
51
56
  root: config.root,
52
57
  srcDir: config.srcDir
53
58
  });
@@ -60,13 +65,13 @@ function astroDBIntegration() {
60
65
  });
61
66
  },
62
67
  "astro:config:done": async ({ config }) => {
63
- const { mod, dependencies } = await loadDbConfigFile(config.root);
68
+ if (command === "preview")
69
+ return;
70
+ const { dbConfig, dependencies, integrationSeedPaths } = await resolveDbConfig(config);
71
+ tables.get = () => dbConfig.tables;
72
+ seedFiles.get = () => integrationSeedPaths;
64
73
  configFileDependencies = dependencies;
65
- dbConfig = dbConfigSchema.parse(mod?.default ?? {}, {
66
- errorMap
67
- });
68
- tables.get = () => dbConfig.tables ?? {};
69
- if (!connectToStudio && !process.env.TEST_IN_MEMORY_DB) {
74
+ if (!connectToStudio) {
70
75
  const dbUrl = new URL(DB_PATH, config.root);
71
76
  if (existsSync(dbUrl)) {
72
77
  await rm(dbUrl);
@@ -1,12 +1,12 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { mkdir, writeFile } from "node:fs/promises";
3
- import { DB_TYPES_FILE, RUNTIME_DRIZZLE_IMPORT, RUNTIME_IMPORT } from "../consts.js";
3
+ import { DB_TYPES_FILE, RUNTIME_CONFIG_IMPORT, RUNTIME_IMPORT } from "../consts.js";
4
4
  async function typegen({ tables, root }) {
5
5
  const content = `// This file is generated by \`studio sync\`
6
6
  declare module 'astro:db' {
7
7
  export const db: import(${RUNTIME_IMPORT}).SqliteDB;
8
8
  export const dbUrl: string;
9
- export * from ${RUNTIME_DRIZZLE_IMPORT};
9
+ export * from ${RUNTIME_CONFIG_IMPORT};
10
10
 
11
11
  ${Object.entries(tables).map(([name, collection]) => generateTableType(name, collection)).join("\n")}
12
12
  }
@@ -3,9 +3,13 @@ import { type VitePlugin } from '../utils.js';
3
3
  export type LateTables = {
4
4
  get: () => DBTables;
5
5
  };
6
+ export type LateSeedFiles = {
7
+ get: () => Array<string | URL>;
8
+ };
6
9
  type VitePluginDBParams = {
7
10
  connectToStudio: false;
8
11
  tables: LateTables;
12
+ seedFiles: LateSeedFiles;
9
13
  srcDir: URL;
10
14
  root: URL;
11
15
  } | {
@@ -17,8 +21,9 @@ type VitePluginDBParams = {
17
21
  };
18
22
  export declare function vitePluginDb(params: VitePluginDBParams): VitePlugin;
19
23
  export declare function getConfigVirtualModContents(): string;
20
- export declare function getLocalVirtualModContents({ tables, shouldSeed, }: {
24
+ export declare function getLocalVirtualModContents({ tables, root, seedFiles, shouldSeed, }: {
21
25
  tables: DBTables;
26
+ seedFiles: Array<string | URL>;
22
27
  root: URL;
23
28
  shouldSeed: boolean;
24
29
  }): string;
@@ -1,47 +1,50 @@
1
+ import { resolve } from "node:path";
1
2
  import { fileURLToPath } from "node:url";
3
+ import { sql } from "drizzle-orm";
4
+ import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
2
5
  import { normalizePath } from "vite";
3
- import { SEED_DEV_FILE_NAME } from "../../runtime/queries.js";
6
+ import { createLocalDatabaseClient } from "../../runtime/db-client.js";
4
7
  import {
5
- DB_PATH,
6
- RUNTIME_CONFIG_IMPORT,
7
- RUNTIME_DRIZZLE_IMPORT,
8
- RUNTIME_IMPORT,
9
- VIRTUAL_MODULE_ID
10
- } from "../consts.js";
8
+ SEED_DEV_FILE_NAME,
9
+ getCreateIndexQueries,
10
+ getCreateTableQuery
11
+ } from "../../runtime/queries.js";
12
+ import { DB_PATH, RUNTIME_CONFIG_IMPORT, RUNTIME_IMPORT, VIRTUAL_MODULE_ID } from "../consts.js";
11
13
  import { getDbDirectoryUrl, getRemoteDatabaseUrl } from "../utils.js";
12
- const LOCAL_DB_VIRTUAL_MODULE_ID = "astro:local";
13
- const resolvedVirtualModuleId = "\0" + VIRTUAL_MODULE_ID;
14
- const resolvedLocalDbVirtualModuleId = LOCAL_DB_VIRTUAL_MODULE_ID + "/local-db";
15
- const resolvedSeedVirtualModuleId = "\0" + VIRTUAL_MODULE_ID + "?shouldSeed";
14
+ const WITH_SEED_VIRTUAL_MODULE_ID = "astro:db:seed";
15
+ const resolved = {
16
+ virtual: "\0" + VIRTUAL_MODULE_ID,
17
+ seedVirtual: "\0" + WITH_SEED_VIRTUAL_MODULE_ID
18
+ };
16
19
  function vitePluginDb(params) {
17
20
  const srcDirPath = normalizePath(fileURLToPath(params.srcDir));
21
+ const seedFilePaths = SEED_DEV_FILE_NAME.map(
22
+ (name) => normalizePath(fileURLToPath(new URL(name, getDbDirectoryUrl(params.root))))
23
+ );
18
24
  return {
19
25
  name: "astro:db",
20
26
  enforce: "pre",
21
27
  async resolveId(id, rawImporter) {
22
- if (id === LOCAL_DB_VIRTUAL_MODULE_ID)
23
- return resolvedLocalDbVirtualModuleId;
24
28
  if (id !== VIRTUAL_MODULE_ID)
25
29
  return;
26
30
  if (params.connectToStudio)
27
- return resolvedVirtualModuleId;
31
+ return resolved.virtual;
28
32
  const importer = rawImporter ? await this.resolve(rawImporter) : null;
29
33
  if (!importer)
30
- return resolvedVirtualModuleId;
34
+ return resolved.virtual;
31
35
  if (importer.id.startsWith(srcDirPath)) {
32
- return resolvedSeedVirtualModuleId;
36
+ return resolved.seedVirtual;
33
37
  }
34
- return resolvedVirtualModuleId;
38
+ return resolved.virtual;
35
39
  },
36
- load(id) {
37
- if (id === resolvedLocalDbVirtualModuleId) {
38
- const dbUrl = new URL(DB_PATH, params.root);
39
- return `import { createLocalDatabaseClient } from ${RUNTIME_IMPORT};
40
- const dbUrl = ${JSON.stringify(dbUrl)};
41
-
42
- export const db = createLocalDatabaseClient({ dbUrl });`;
40
+ async load(id) {
41
+ if (seedFilePaths.some((f) => id === f)) {
42
+ await recreateTables({
43
+ db: createLocalDatabaseClient({ dbUrl: new URL(DB_PATH, params.root).href }),
44
+ tables: params.tables.get()
45
+ });
43
46
  }
44
- if (id !== resolvedVirtualModuleId && id !== resolvedSeedVirtualModuleId)
47
+ if (id !== resolved.virtual && id !== resolved.seedVirtual)
45
48
  return;
46
49
  if (params.connectToStudio) {
47
50
  return getStudioVirtualModContents({
@@ -52,7 +55,8 @@ function vitePluginDb(params) {
52
55
  return getLocalVirtualModContents({
53
56
  root: params.root,
54
57
  tables: params.tables.get(),
55
- shouldSeed: id === resolvedSeedVirtualModuleId
58
+ seedFiles: params.seedFiles.get(),
59
+ shouldSeed: id === resolved.seedVirtual
56
60
  });
57
61
  }
58
62
  };
@@ -62,26 +66,35 @@ function getConfigVirtualModContents() {
62
66
  }
63
67
  function getLocalVirtualModContents({
64
68
  tables,
69
+ root,
70
+ seedFiles,
65
71
  shouldSeed
66
72
  }) {
67
- const seedFilePaths = SEED_DEV_FILE_NAME.map(
73
+ const userSeedFilePaths = SEED_DEV_FILE_NAME.map(
68
74
  // Format as /db/[name].ts
69
75
  // for Vite import.meta.glob
70
76
  (name) => new URL(name, getDbDirectoryUrl("file:///")).pathname
71
77
  );
78
+ const resolveId = (id) => id.startsWith(".") ? resolve(fileURLToPath(root), id) : id;
79
+ const integrationSeedFilePaths = seedFiles.map(
80
+ (pathOrUrl) => typeof pathOrUrl === "string" ? resolveId(pathOrUrl) : pathOrUrl.pathname
81
+ );
82
+ const integrationSeedImports = integrationSeedFilePaths.map(
83
+ (filePath) => `() => import(${JSON.stringify(filePath)})`
84
+ );
85
+ const dbUrl = new URL(DB_PATH, root);
72
86
  return `
73
- import { asDrizzleTable, seedLocal } from ${RUNTIME_IMPORT};
74
- import { db as _db } from ${JSON.stringify(LOCAL_DB_VIRTUAL_MODULE_ID)};
87
+ import { asDrizzleTable, createLocalDatabaseClient } from ${RUNTIME_IMPORT};
88
+ ${shouldSeed ? `import { seedLocal } from ${RUNTIME_IMPORT};` : ""}
75
89
 
76
- export const db = _db;
90
+ const dbUrl = ${JSON.stringify(dbUrl)};
91
+ export const db = createLocalDatabaseClient({ dbUrl });
77
92
 
78
93
  ${shouldSeed ? `await seedLocal({
79
- db: _db,
80
- tables: ${JSON.stringify(tables)},
81
- fileGlob: import.meta.glob(${JSON.stringify(seedFilePaths)}),
82
- })` : ""}
94
+ userSeedGlob: import.meta.glob(${JSON.stringify(userSeedFilePaths)}, { eager: true }),
95
+ integrationSeedImports: [${integrationSeedImports.join(",")}],
96
+ });` : ""}
83
97
 
84
- export * from ${RUNTIME_DRIZZLE_IMPORT};
85
98
  export * from ${RUNTIME_CONFIG_IMPORT};
86
99
 
87
100
  ${getStringifiedCollectionExports(tables)}`;
@@ -97,7 +110,7 @@ export const db = await createRemoteDatabaseClient(${JSON.stringify(
97
110
  appToken
98
111
  // Respect runtime env for user overrides in SSR
99
112
  )}, import.meta.env.ASTRO_STUDIO_REMOTE_DB_URL ?? ${JSON.stringify(getRemoteDatabaseUrl())});
100
- export * from ${RUNTIME_DRIZZLE_IMPORT};
113
+
101
114
  export * from ${RUNTIME_CONFIG_IMPORT};
102
115
 
103
116
  ${getStringifiedCollectionExports(tables)}
@@ -110,6 +123,20 @@ function getStringifiedCollectionExports(tables) {
110
123
  )}, false)`
111
124
  ).join("\n");
112
125
  }
126
+ const sqlite = new SQLiteAsyncDialect();
127
+ async function recreateTables({ db, tables }) {
128
+ const setupQueries = [];
129
+ for (const [name, table] of Object.entries(tables)) {
130
+ const dropQuery = sql.raw(`DROP TABLE IF EXISTS ${sqlite.escapeName(name)}`);
131
+ const createQuery = sql.raw(getCreateTableQuery(name, table));
132
+ const indexQueries = getCreateIndexQueries(name, table);
133
+ setupQueries.push(dropQuery, createQuery, ...indexQueries.map((s) => sql.raw(s)));
134
+ }
135
+ await db.batch([
136
+ db.run(sql`pragma defer_foreign_keys=true;`),
137
+ ...setupQueries.map((q) => db.run(q))
138
+ ]);
139
+ }
113
140
  export {
114
141
  getConfigVirtualModContents,
115
142
  getLocalVirtualModContents,