@astrojs/db 0.6.5 → 0.7.1
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.
- package/dist/core/cli/commands/execute/index.js +30 -8
- package/dist/core/cli/commands/push/index.js +3 -3
- package/dist/core/cli/commands/shell/index.d.ts +1 -1
- package/dist/core/cli/commands/shell/index.js +23 -7
- package/dist/core/cli/commands/verify/index.js +1 -1
- package/dist/core/cli/index.js +2 -4
- package/dist/core/cli/migration-queries.d.ts +1 -1
- package/dist/core/cli/migration-queries.js +3 -2
- package/dist/core/consts.d.ts +2 -2
- package/dist/core/consts.js +4 -3
- package/dist/core/errors.d.ts +3 -0
- package/dist/core/errors.js +19 -2
- package/dist/core/integration/index.js +16 -11
- package/dist/core/integration/typegen.js +2 -2
- package/dist/core/integration/vite-plugin-db.d.ts +6 -1
- package/dist/core/integration/vite-plugin-db.js +63 -36
- package/dist/core/load-file.d.ts +226 -4
- package/dist/core/load-file.js +73 -5
- package/dist/core/types.d.ts +12 -5
- package/dist/core/utils.d.ts +3 -1
- package/dist/core/utils.js +4 -0
- package/dist/runtime/config.d.ts +3 -2
- package/dist/runtime/config.js +48 -3
- package/dist/runtime/db-client.js +90 -40
- package/dist/runtime/index.d.ts +8 -1
- package/dist/runtime/index.js +32 -1
- package/dist/runtime/queries.d.ts +1 -11
- package/dist/runtime/queries.js +3 -40
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +3 -1
- package/package.json +4 -11
- package/virtual.d.ts +1 -1
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
3
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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 {
|
|
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";
|
|
@@ -18,7 +18,7 @@ async function cmd({
|
|
|
18
18
|
const appToken = await getManagedAppTokenOrExit(flags.token);
|
|
19
19
|
const productionSnapshot = await getProductionCurrentSnapshot({ appToken: appToken.token });
|
|
20
20
|
const currentSnapshot = createCurrentSnapshot(dbConfig);
|
|
21
|
-
const isFromScratch = isForceReset ||
|
|
21
|
+
const isFromScratch = isForceReset || !productionSnapshot;
|
|
22
22
|
const { queries: migrationQueries, confirmations } = await getMigrationQueries({
|
|
23
23
|
oldSnapshot: isFromScratch ? createEmptySnapshot() : productionSnapshot,
|
|
24
24
|
newSnapshot: currentSnapshot
|
|
@@ -57,7 +57,7 @@ async function pushSchema({
|
|
|
57
57
|
const requestBody = {
|
|
58
58
|
snapshot: currentSnapshot,
|
|
59
59
|
sql: statements,
|
|
60
|
-
|
|
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 {
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
@@ -15,7 +15,7 @@ async function cmd({
|
|
|
15
15
|
const productionSnapshot = await getProductionCurrentSnapshot({ appToken: appToken.token });
|
|
16
16
|
const currentSnapshot = createCurrentSnapshot(dbConfig);
|
|
17
17
|
const { queries: migrationQueries, confirmations } = await getMigrationQueries({
|
|
18
|
-
oldSnapshot:
|
|
18
|
+
oldSnapshot: productionSnapshot || createEmptySnapshot(),
|
|
19
19
|
newSnapshot: currentSnapshot
|
|
20
20
|
});
|
|
21
21
|
const result = { exitCode: 0, message: "", code: "", data: void 0 };
|
package/dist/core/cli/index.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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");
|
|
@@ -16,7 +16,7 @@ export declare function getCollectionChangeQueries({ collectionName, oldCollecti
|
|
|
16
16
|
}>;
|
|
17
17
|
export declare function getProductionCurrentSnapshot({ appToken, }: {
|
|
18
18
|
appToken: string;
|
|
19
|
-
}): Promise<DBSnapshot>;
|
|
19
|
+
}): Promise<DBSnapshot | undefined>;
|
|
20
20
|
export declare function createCurrentSnapshot({ tables }: DBConfig): DBSnapshot;
|
|
21
21
|
export declare function createEmptySnapshot(): DBSnapshot;
|
|
22
22
|
export declare function formatDataLossMessage(confirmations: string[], isColor?: boolean): string;
|
|
@@ -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 {
|
|
339
|
+
return { version: MIGRATION_VERSION, schema };
|
|
339
340
|
}
|
|
340
341
|
function createEmptySnapshot() {
|
|
341
|
-
return {
|
|
342
|
+
return { version: MIGRATION_VERSION, schema: {} };
|
|
342
343
|
}
|
|
343
344
|
function formatDataLossMessage(confirmations, isColor = true) {
|
|
344
345
|
const messages = [];
|
package/dist/core/consts.d.ts
CHANGED
|
@@ -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
|
|
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";
|
package/dist/core/consts.js
CHANGED
|
@@ -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 = "
|
|
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
|
};
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -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;
|
package/dist/core/errors.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bold, cyan,
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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 ${
|
|
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 {
|
|
6
|
+
import { createLocalDatabaseClient } from "../../runtime/db-client.js";
|
|
4
7
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
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
|
|
31
|
+
return resolved.virtual;
|
|
28
32
|
const importer = rawImporter ? await this.resolve(rawImporter) : null;
|
|
29
33
|
if (!importer)
|
|
30
|
-
return
|
|
34
|
+
return resolved.virtual;
|
|
31
35
|
if (importer.id.startsWith(srcDirPath)) {
|
|
32
|
-
return
|
|
36
|
+
return resolved.seedVirtual;
|
|
33
37
|
}
|
|
34
|
-
return
|
|
38
|
+
return resolved.virtual;
|
|
35
39
|
},
|
|
36
|
-
load(id) {
|
|
37
|
-
if (id ===
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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 !==
|
|
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
|
-
|
|
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
|
|
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,
|
|
74
|
-
import {
|
|
87
|
+
import { asDrizzleTable, createLocalDatabaseClient } from ${RUNTIME_IMPORT};
|
|
88
|
+
${shouldSeed ? `import { seedLocal } from ${RUNTIME_IMPORT};` : ""}
|
|
75
89
|
|
|
76
|
-
|
|
90
|
+
const dbUrl = ${JSON.stringify(dbUrl)};
|
|
91
|
+
export const db = createLocalDatabaseClient({ dbUrl });
|
|
77
92
|
|
|
78
93
|
${shouldSeed ? `await seedLocal({
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
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,
|