@astrojs/db 0.4.1 → 0.6.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.
- package/dist/core/cli/commands/execute/index.d.ts +8 -0
- package/dist/core/cli/commands/execute/index.js +32 -0
- package/dist/core/cli/commands/link/index.d.ts +20 -8
- package/dist/core/cli/commands/link/index.js +191 -31
- package/dist/core/cli/commands/login/index.d.ts +4 -2
- package/dist/core/cli/commands/login/index.js +31 -22
- package/dist/core/cli/commands/logout/index.d.ts +1 -6
- package/dist/core/cli/commands/logout/index.js +1 -1
- package/dist/core/cli/commands/push/index.d.ts +4 -2
- package/dist/core/cli/commands/push/index.js +30 -170
- package/dist/core/cli/commands/shell/index.d.ts +4 -2
- package/dist/core/cli/commands/shell/index.js +3 -1
- package/dist/core/cli/commands/verify/index.d.ts +4 -2
- package/dist/core/cli/commands/verify/index.js +23 -37
- package/dist/core/cli/index.d.ts +1 -1
- package/dist/core/cli/index.js +26 -17
- package/dist/core/cli/migration-queries.d.ts +8 -13
- package/dist/core/cli/migration-queries.js +65 -121
- package/dist/core/consts.d.ts +2 -0
- package/dist/core/consts.js +4 -0
- package/dist/core/errors.d.ts +9 -7
- package/dist/core/errors.js +44 -43
- package/dist/core/integration/file-url.js +2 -5
- package/dist/core/integration/index.js +56 -112
- package/dist/core/integration/typegen.js +3 -13
- package/dist/core/integration/vite-plugin-db.d.ts +9 -5
- package/dist/core/integration/vite-plugin-db.js +66 -23
- package/dist/core/integration/vite-plugin-inject-env-ts.d.ts +1 -1
- package/dist/core/load-file.d.ts +31 -0
- package/dist/core/load-file.js +98 -0
- package/dist/core/tokens.js +1 -1
- package/dist/core/types.d.ts +1148 -5306
- package/dist/core/types.js +19 -85
- package/dist/core/utils.d.ts +1 -0
- package/dist/core/utils.js +4 -0
- package/dist/index.d.ts +2 -3
- package/dist/index.js +3 -5
- package/dist/runtime/config.d.ts +147 -0
- package/dist/runtime/config.js +42 -0
- package/dist/runtime/db-client.d.ts +2 -9
- package/dist/runtime/db-client.js +8 -39
- package/dist/runtime/index.d.ts +5 -4
- package/dist/runtime/index.js +12 -10
- package/dist/{core → runtime}/queries.d.ts +20 -17
- package/dist/{core → runtime}/queries.js +67 -91
- package/dist/runtime/types.d.ts +3 -3
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +4 -0
- package/index.d.ts +5 -3
- package/package.json +20 -5
- package/config-augment.d.ts +0 -4
- package/dist/core/cli/commands/gen/index.d.ts +0 -6
- package/dist/core/cli/commands/gen/index.js +0 -39
- package/dist/core/cli/migrations.d.ts +0 -34
- package/dist/core/cli/migrations.js +0 -129
- package/dist/core/integration/load-astro-config.d.ts +0 -6
- package/dist/core/integration/load-astro-config.js +0 -79
|
@@ -1,48 +1,50 @@
|
|
|
1
|
-
import * as color from "kleur/colors";
|
|
2
1
|
import deepDiff from "deep-diff";
|
|
3
|
-
import {
|
|
4
|
-
columnSchema
|
|
5
|
-
} from "../types.js";
|
|
6
2
|
import { SQLiteAsyncDialect } from "drizzle-orm/sqlite-core";
|
|
3
|
+
import * as color from "kleur/colors";
|
|
7
4
|
import { customAlphabet } from "nanoid";
|
|
8
|
-
import
|
|
5
|
+
import { hasPrimaryKey } from "../../runtime/index.js";
|
|
9
6
|
import {
|
|
10
7
|
getCreateIndexQueries,
|
|
11
8
|
getCreateTableQuery,
|
|
9
|
+
getDropTableIfExistsQuery,
|
|
12
10
|
getModifiers,
|
|
13
11
|
getReferencesConfig,
|
|
14
12
|
hasDefault,
|
|
15
13
|
schemaTypeToSqlType
|
|
16
|
-
} from "
|
|
17
|
-
import { hasPrimaryKey } from "../../runtime/index.js";
|
|
14
|
+
} from "../../runtime/queries.js";
|
|
18
15
|
import { isSerializedSQL } from "../../runtime/types.js";
|
|
16
|
+
import { RENAME_COLUMN_ERROR, RENAME_TABLE_ERROR } from "../errors.js";
|
|
17
|
+
import {
|
|
18
|
+
columnSchema
|
|
19
|
+
} from "../types.js";
|
|
20
|
+
import { getRemoteDatabaseUrl } from "../utils.js";
|
|
19
21
|
const sqlite = new SQLiteAsyncDialect();
|
|
20
22
|
const genTempTableName = customAlphabet("abcdefghijklmnopqrstuvwxyz", 10);
|
|
21
23
|
async function getMigrationQueries({
|
|
22
24
|
oldSnapshot,
|
|
23
|
-
newSnapshot
|
|
24
|
-
ambiguityResponses
|
|
25
|
+
newSnapshot
|
|
25
26
|
}) {
|
|
26
27
|
const queries = [];
|
|
27
28
|
const confirmations = [];
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
const addedCollections = getAddedCollections(oldSnapshot, newSnapshot);
|
|
30
|
+
const droppedTables = getDroppedCollections(oldSnapshot, newSnapshot);
|
|
31
|
+
const notDeprecatedDroppedTables = Object.fromEntries(
|
|
32
|
+
Object.entries(droppedTables).filter(([, table]) => !table.deprecated)
|
|
33
|
+
);
|
|
34
|
+
if (!isEmpty(addedCollections) && !isEmpty(notDeprecatedDroppedTables)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
RENAME_TABLE_ERROR(
|
|
37
|
+
Object.keys(addedCollections)[0],
|
|
38
|
+
Object.keys(notDeprecatedDroppedTables)[0]
|
|
39
|
+
)
|
|
40
|
+
);
|
|
40
41
|
}
|
|
41
|
-
for (const [collectionName, collection] of Object.entries(
|
|
42
|
+
for (const [collectionName, collection] of Object.entries(addedCollections)) {
|
|
43
|
+
queries.push(getDropTableIfExistsQuery(collectionName));
|
|
42
44
|
queries.push(getCreateTableQuery(collectionName, collection));
|
|
43
45
|
queries.push(...getCreateIndexQueries(collectionName, collection));
|
|
44
46
|
}
|
|
45
|
-
for (const [collectionName] of Object.entries(
|
|
47
|
+
for (const [collectionName] of Object.entries(droppedTables)) {
|
|
46
48
|
const dropQuery = `DROP TABLE ${sqlite.escapeName(collectionName)}`;
|
|
47
49
|
queries.push(dropQuery);
|
|
48
50
|
}
|
|
@@ -50,6 +52,19 @@ async function getMigrationQueries({
|
|
|
50
52
|
const oldCollection = oldSnapshot.schema[collectionName];
|
|
51
53
|
if (!oldCollection)
|
|
52
54
|
continue;
|
|
55
|
+
const addedColumns = getAdded(oldCollection.columns, newCollection.columns);
|
|
56
|
+
const droppedColumns = getDropped(oldCollection.columns, newCollection.columns);
|
|
57
|
+
const notDeprecatedDroppedColumns = Object.fromEntries(
|
|
58
|
+
Object.entries(droppedColumns).filter(([key, col]) => !col.schema.deprecated)
|
|
59
|
+
);
|
|
60
|
+
if (!isEmpty(addedColumns) && !isEmpty(notDeprecatedDroppedColumns)) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
RENAME_COLUMN_ERROR(
|
|
63
|
+
`${collectionName}.${Object.keys(addedColumns)[0]}`,
|
|
64
|
+
`${collectionName}.${Object.keys(notDeprecatedDroppedColumns)[0]}`
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
53
68
|
const result = await getCollectionChangeQueries({
|
|
54
69
|
collectionName,
|
|
55
70
|
oldCollection,
|
|
@@ -63,14 +78,13 @@ async function getMigrationQueries({
|
|
|
63
78
|
async function getCollectionChangeQueries({
|
|
64
79
|
collectionName,
|
|
65
80
|
oldCollection,
|
|
66
|
-
newCollection
|
|
67
|
-
ambiguityResponses
|
|
81
|
+
newCollection
|
|
68
82
|
}) {
|
|
69
83
|
const queries = [];
|
|
70
84
|
const confirmations = [];
|
|
71
85
|
const updated = getUpdatedColumns(oldCollection.columns, newCollection.columns);
|
|
72
|
-
|
|
73
|
-
|
|
86
|
+
const added = getAdded(oldCollection.columns, newCollection.columns);
|
|
87
|
+
const dropped = getDropped(oldCollection.columns, newCollection.columns);
|
|
74
88
|
const hasForeignKeyChanges = Boolean(
|
|
75
89
|
deepDiff(oldCollection.foreignKeys, newCollection.foreignKeys)
|
|
76
90
|
);
|
|
@@ -84,12 +98,6 @@ async function getCollectionChangeQueries({
|
|
|
84
98
|
confirmations
|
|
85
99
|
};
|
|
86
100
|
}
|
|
87
|
-
if (!hasForeignKeyChanges && !isEmpty(added) && !isEmpty(dropped)) {
|
|
88
|
-
const resolved = await resolveColumnRenames(collectionName, added, dropped, ambiguityResponses);
|
|
89
|
-
added = resolved.added;
|
|
90
|
-
dropped = resolved.dropped;
|
|
91
|
-
queries.push(...getColumnRenameQueries(collectionName, resolved.renamed));
|
|
92
|
-
}
|
|
93
101
|
if (!hasForeignKeyChanges && isEmpty(updated) && Object.values(dropped).every(canAlterTableDropColumn) && Object.values(added).every(canAlterTableAddColumn)) {
|
|
94
102
|
queries.push(
|
|
95
103
|
...getAlterTableQueries(collectionName, added, dropped),
|
|
@@ -158,82 +166,6 @@ function getChangeIndexQueries({
|
|
|
158
166
|
queries.push(...getCreateIndexQueries(collectionName, { indexes: added }));
|
|
159
167
|
return queries;
|
|
160
168
|
}
|
|
161
|
-
async function resolveColumnRenames(collectionName, mightAdd, mightDrop, ambiguityResponses) {
|
|
162
|
-
const added = {};
|
|
163
|
-
const dropped = {};
|
|
164
|
-
const renamed = [];
|
|
165
|
-
for (const [columnName, column] of Object.entries(mightAdd)) {
|
|
166
|
-
let oldColumnName = ambiguityResponses ? ambiguityResponses.columnRenames[collectionName]?.[columnName] ?? "__NEW__" : void 0;
|
|
167
|
-
if (!oldColumnName) {
|
|
168
|
-
const res = await prompts(
|
|
169
|
-
{
|
|
170
|
-
type: "select",
|
|
171
|
-
name: "columnName",
|
|
172
|
-
message: "New column " + color.blue(color.bold(`${collectionName}.${columnName}`)) + " detected. Was this renamed from an existing column?",
|
|
173
|
-
choices: [
|
|
174
|
-
{ title: "New column (not renamed from existing)", value: "__NEW__" },
|
|
175
|
-
...Object.keys(mightDrop).filter((key) => !(key in renamed)).map((key) => ({ title: key, value: key }))
|
|
176
|
-
]
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
onCancel: () => {
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
);
|
|
184
|
-
oldColumnName = res.columnName;
|
|
185
|
-
}
|
|
186
|
-
if (oldColumnName === "__NEW__") {
|
|
187
|
-
added[columnName] = column;
|
|
188
|
-
} else {
|
|
189
|
-
renamed.push({ from: oldColumnName, to: columnName });
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
for (const [droppedColumnName, droppedColumn] of Object.entries(mightDrop)) {
|
|
193
|
-
if (!renamed.find((r) => r.from === droppedColumnName)) {
|
|
194
|
-
dropped[droppedColumnName] = droppedColumn;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return { added, dropped, renamed };
|
|
198
|
-
}
|
|
199
|
-
async function resolveCollectionRenames(mightAdd, mightDrop, ambiguityResponses) {
|
|
200
|
-
const added = {};
|
|
201
|
-
const dropped = {};
|
|
202
|
-
const renamed = [];
|
|
203
|
-
for (const [collectionName, collection] of Object.entries(mightAdd)) {
|
|
204
|
-
let oldCollectionName = ambiguityResponses ? ambiguityResponses.collectionRenames[collectionName] ?? "__NEW__" : void 0;
|
|
205
|
-
if (!oldCollectionName) {
|
|
206
|
-
const res = await prompts(
|
|
207
|
-
{
|
|
208
|
-
type: "select",
|
|
209
|
-
name: "collectionName",
|
|
210
|
-
message: "New collection " + color.blue(color.bold(collectionName)) + " detected. Was this renamed from an existing collection?",
|
|
211
|
-
choices: [
|
|
212
|
-
{ title: "New collection (not renamed from existing)", value: "__NEW__" },
|
|
213
|
-
...Object.keys(mightDrop).filter((key) => !(key in renamed)).map((key) => ({ title: key, value: key }))
|
|
214
|
-
]
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
onCancel: () => {
|
|
218
|
-
process.exit(1);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
);
|
|
222
|
-
oldCollectionName = res.collectionName;
|
|
223
|
-
}
|
|
224
|
-
if (oldCollectionName === "__NEW__") {
|
|
225
|
-
added[collectionName] = collection;
|
|
226
|
-
} else {
|
|
227
|
-
renamed.push({ from: oldCollectionName, to: collectionName });
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
for (const [droppedCollectionName, droppedCollection] of Object.entries(mightDrop)) {
|
|
231
|
-
if (!renamed.find((r) => r.from === droppedCollectionName)) {
|
|
232
|
-
dropped[droppedCollectionName] = droppedCollection;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
return { added, dropped, renamed };
|
|
236
|
-
}
|
|
237
169
|
function getAddedCollections(oldCollections, newCollections) {
|
|
238
170
|
const added = {};
|
|
239
171
|
for (const [key, newCollection] of Object.entries(newCollections.schema)) {
|
|
@@ -250,17 +182,6 @@ function getDroppedCollections(oldCollections, newCollections) {
|
|
|
250
182
|
}
|
|
251
183
|
return dropped;
|
|
252
184
|
}
|
|
253
|
-
function getColumnRenameQueries(unescapedCollectionName, renamed) {
|
|
254
|
-
const queries = [];
|
|
255
|
-
const collectionName = sqlite.escapeName(unescapedCollectionName);
|
|
256
|
-
for (const { from, to } of renamed) {
|
|
257
|
-
const q = `ALTER TABLE ${collectionName} RENAME COLUMN ${sqlite.escapeName(
|
|
258
|
-
from
|
|
259
|
-
)} TO ${sqlite.escapeName(to)}`;
|
|
260
|
-
queries.push(q);
|
|
261
|
-
}
|
|
262
|
-
return queries;
|
|
263
|
-
}
|
|
264
185
|
function getAlterTableQueries(unescapedCollectionName, added, dropped) {
|
|
265
186
|
const queries = [];
|
|
266
187
|
const collectionName = sqlite.escapeName(unescapedCollectionName);
|
|
@@ -412,7 +333,30 @@ function canChangeTypeWithoutQuery(oldColumn, newColumn) {
|
|
|
412
333
|
function hasRuntimeDefault(column) {
|
|
413
334
|
return !!(column.schema.default && isSerializedSQL(column.schema.default));
|
|
414
335
|
}
|
|
336
|
+
async function getProductionCurrentSnapshot({
|
|
337
|
+
appToken
|
|
338
|
+
}) {
|
|
339
|
+
const url = new URL("/db/schema", getRemoteDatabaseUrl());
|
|
340
|
+
const response = await fetch(url, {
|
|
341
|
+
method: "POST",
|
|
342
|
+
headers: new Headers({
|
|
343
|
+
Authorization: `Bearer ${appToken}`
|
|
344
|
+
})
|
|
345
|
+
});
|
|
346
|
+
const result = await response.json();
|
|
347
|
+
return result.data;
|
|
348
|
+
}
|
|
349
|
+
function createCurrentSnapshot({ tables = {} }) {
|
|
350
|
+
const schema = JSON.parse(JSON.stringify(tables));
|
|
351
|
+
return { experimentalVersion: 1, schema };
|
|
352
|
+
}
|
|
353
|
+
function createEmptySnapshot() {
|
|
354
|
+
return { experimentalVersion: 1, schema: {} };
|
|
355
|
+
}
|
|
415
356
|
export {
|
|
357
|
+
createCurrentSnapshot,
|
|
358
|
+
createEmptySnapshot,
|
|
416
359
|
getCollectionChangeQueries,
|
|
417
|
-
getMigrationQueries
|
|
360
|
+
getMigrationQueries,
|
|
361
|
+
getProductionCurrentSnapshot
|
|
418
362
|
};
|
package/dist/core/consts.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export declare const PACKAGE_NAME: any;
|
|
2
2
|
export declare const RUNTIME_IMPORT: string;
|
|
3
3
|
export declare const RUNTIME_DRIZZLE_IMPORT: string;
|
|
4
|
+
export declare const RUNTIME_CONFIG_IMPORT: string;
|
|
4
5
|
export declare const DB_TYPES_FILE = "db-types.d.ts";
|
|
5
6
|
export declare const VIRTUAL_MODULE_ID = "astro:db";
|
|
6
7
|
export declare const DB_PATH = ".astro/content.db";
|
|
8
|
+
export declare const CONFIG_FILE_NAMES: string[];
|
package/dist/core/consts.js
CHANGED
|
@@ -4,13 +4,17 @@ const PACKAGE_NAME = JSON.parse(
|
|
|
4
4
|
).name;
|
|
5
5
|
const RUNTIME_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime`);
|
|
6
6
|
const RUNTIME_DRIZZLE_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime/drizzle`);
|
|
7
|
+
const RUNTIME_CONFIG_IMPORT = JSON.stringify(`${PACKAGE_NAME}/runtime/config`);
|
|
7
8
|
const DB_TYPES_FILE = "db-types.d.ts";
|
|
8
9
|
const VIRTUAL_MODULE_ID = "astro:db";
|
|
9
10
|
const DB_PATH = ".astro/content.db";
|
|
11
|
+
const CONFIG_FILE_NAMES = ["config.ts", "config.js", "config.mts", "config.mjs"];
|
|
10
12
|
export {
|
|
13
|
+
CONFIG_FILE_NAMES,
|
|
11
14
|
DB_PATH,
|
|
12
15
|
DB_TYPES_FILE,
|
|
13
16
|
PACKAGE_NAME,
|
|
17
|
+
RUNTIME_CONFIG_IMPORT,
|
|
14
18
|
RUNTIME_DRIZZLE_IMPORT,
|
|
15
19
|
RUNTIME_IMPORT,
|
|
16
20
|
VIRTUAL_MODULE_ID
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export declare const MISSING_SESSION_ID_ERROR: string;
|
|
2
2
|
export declare const MISSING_PROJECT_ID_ERROR: string;
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
5
|
-
export declare const
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const
|
|
3
|
+
export declare const MISSING_EXECUTE_PATH_ERROR: string;
|
|
4
|
+
export declare const RENAME_TABLE_ERROR: (oldTable: string, newTable: string) => string;
|
|
5
|
+
export declare const RENAME_COLUMN_ERROR: (oldSelector: string, newSelector: string) => string;
|
|
6
|
+
export declare const FILE_NOT_FOUND_ERROR: (path: string) => string;
|
|
7
|
+
export declare const SEED_ERROR: (error: string) => string;
|
|
8
|
+
export declare const REFERENCE_DNE_ERROR: (columnName: string) => string;
|
|
9
|
+
export declare const FOREIGN_KEY_DNE_ERROR: (tableName: string) => string;
|
|
10
|
+
export declare const FOREIGN_KEY_REFERENCES_LENGTH_ERROR: (tableName: string) => string;
|
|
11
|
+
export declare const FOREIGN_KEY_REFERENCES_EMPTY_ERROR: (tableName: string) => string;
|
package/dist/core/errors.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cyan,
|
|
1
|
+
import { bold, cyan, green, red, yellow } from "kleur/colors";
|
|
2
2
|
const MISSING_SESSION_ID_ERROR = `${red("\u25B6 Login required!")}
|
|
3
3
|
|
|
4
4
|
To authenticate with Astro Studio, run
|
|
@@ -9,56 +9,57 @@ const MISSING_PROJECT_ID_ERROR = `${red("\u25B6 Directory not linked.")}
|
|
|
9
9
|
To link this directory to an Astro Studio project, run
|
|
10
10
|
${cyan("astro db link")}
|
|
11
11
|
`;
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
)} option.`
|
|
16
|
-
)}
|
|
17
|
-
|
|
18
|
-
Visit ${cyan("https://astro.build/studio")} to create your account
|
|
19
|
-
and set ${green("studio: true")} in your astro.config.mjs file to enable Studio.
|
|
20
|
-
`;
|
|
21
|
-
const UNSAFE_WRITABLE_WARNING = `${yellow(
|
|
22
|
-
"unsafeWritable"
|
|
23
|
-
)} option is enabled and you are using writable tables.
|
|
24
|
-
Redeploying your app may result in wiping away your database.
|
|
25
|
-
I hope you know what you are doing.
|
|
12
|
+
const MISSING_EXECUTE_PATH_ERROR = `${red(
|
|
13
|
+
"\u25B6 No file path provided."
|
|
14
|
+
)} Provide a path by running ${cyan("astro db execute <path>")}
|
|
26
15
|
`;
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
16
|
+
const RENAME_TABLE_ERROR = (oldTable, newTable) => {
|
|
17
|
+
return red("\u25B6 Potential table rename detected: " + oldTable + ", " + newTable) + `
|
|
18
|
+
You cannot add and remove tables in the same schema update batch.
|
|
19
|
+
To resolve, add a 'deprecated: true' flag to '${oldTable}' instead.`;
|
|
20
|
+
};
|
|
21
|
+
const RENAME_COLUMN_ERROR = (oldSelector, newSelector) => {
|
|
22
|
+
return red("\u25B6 Potential column rename detected: " + oldSelector + ", " + newSelector) + `
|
|
23
|
+
You cannot add and remove columns in the same table.
|
|
24
|
+
To resolve, add a 'deprecated: true' flag to '${oldSelector}' instead.`;
|
|
25
|
+
};
|
|
26
|
+
const FILE_NOT_FOUND_ERROR = (path) => `${red("\u25B6 File not found:")} ${bold(path)}
|
|
31
27
|
`;
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
)}
|
|
28
|
+
const SEED_ERROR = (error) => {
|
|
29
|
+
return `${red(`Error while seeding database:`)}
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
${error}`;
|
|
32
|
+
};
|
|
33
|
+
const REFERENCE_DNE_ERROR = (columnName) => {
|
|
34
|
+
return `Column ${bold(
|
|
35
|
+
columnName
|
|
36
|
+
)} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
|
|
37
|
+
};
|
|
38
|
+
const FOREIGN_KEY_DNE_ERROR = (tableName) => {
|
|
39
|
+
return `Table ${bold(
|
|
43
40
|
tableName
|
|
44
|
-
)}
|
|
41
|
+
)} references a table that does not exist. Did you apply the referenced table to the \`tables\` object in your db config?`;
|
|
45
42
|
};
|
|
46
|
-
const
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
const FOREIGN_KEY_REFERENCES_LENGTH_ERROR = (tableName) => {
|
|
44
|
+
return `Foreign key on ${bold(
|
|
45
|
+
tableName
|
|
46
|
+
)} is misconfigured. \`columns\` and \`references\` must be the same length.`;
|
|
50
47
|
};
|
|
51
|
-
const
|
|
52
|
-
return
|
|
48
|
+
const FOREIGN_KEY_REFERENCES_EMPTY_ERROR = (tableName) => {
|
|
49
|
+
return `Foreign key on ${bold(
|
|
50
|
+
tableName
|
|
51
|
+
)} is misconfigured. \`references\` array cannot be empty.`;
|
|
53
52
|
};
|
|
54
53
|
export {
|
|
55
|
-
|
|
54
|
+
FILE_NOT_FOUND_ERROR,
|
|
55
|
+
FOREIGN_KEY_DNE_ERROR,
|
|
56
|
+
FOREIGN_KEY_REFERENCES_EMPTY_ERROR,
|
|
57
|
+
FOREIGN_KEY_REFERENCES_LENGTH_ERROR,
|
|
58
|
+
MISSING_EXECUTE_PATH_ERROR,
|
|
56
59
|
MISSING_PROJECT_ID_ERROR,
|
|
57
60
|
MISSING_SESSION_ID_ERROR,
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
STUDIO_CONFIG_MISSING_WRITABLE_TABLE_ERROR,
|
|
63
|
-
UNSAFE_WRITABLE_WARNING
|
|
61
|
+
REFERENCE_DNE_ERROR,
|
|
62
|
+
RENAME_COLUMN_ERROR,
|
|
63
|
+
RENAME_TABLE_ERROR,
|
|
64
|
+
SEED_ERROR
|
|
64
65
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import { pathToFileURL } from "node:url";
|
|
3
2
|
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
4
|
async function copyFile(toDir, fromUrl, toUrl) {
|
|
5
5
|
await fs.promises.mkdir(toDir, { recursive: true });
|
|
6
6
|
await fs.promises.rename(fromUrl, toUrl);
|
|
@@ -61,10 +61,7 @@ function fileURLIntegration() {
|
|
|
61
61
|
}
|
|
62
62
|
await Promise.all(unlinks);
|
|
63
63
|
const assetDir = new URL(config.build.assets, config.outDir);
|
|
64
|
-
|
|
65
|
-
if (!assetFiles.length) {
|
|
66
|
-
await fs.promises.rmdir(assetDir);
|
|
67
|
-
}
|
|
64
|
+
await fs.promises.rmdir(assetDir).catch(() => []);
|
|
68
65
|
} else {
|
|
69
66
|
const moves = [];
|
|
70
67
|
for (const fileName of fileNames) {
|
|
@@ -1,66 +1,27 @@
|
|
|
1
|
-
var __knownSymbol = (name, symbol) => {
|
|
2
|
-
return (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
|
3
|
-
};
|
|
4
|
-
var __using = (stack, value, async) => {
|
|
5
|
-
if (value != null) {
|
|
6
|
-
if (typeof value !== "object" && typeof value !== "function")
|
|
7
|
-
throw TypeError("Object expected");
|
|
8
|
-
var dispose;
|
|
9
|
-
if (async)
|
|
10
|
-
dispose = value[__knownSymbol("asyncDispose")];
|
|
11
|
-
if (dispose === void 0)
|
|
12
|
-
dispose = value[__knownSymbol("dispose")];
|
|
13
|
-
if (typeof dispose !== "function")
|
|
14
|
-
throw TypeError("Object not disposable");
|
|
15
|
-
stack.push([async, dispose, value]);
|
|
16
|
-
} else if (async) {
|
|
17
|
-
stack.push([async]);
|
|
18
|
-
}
|
|
19
|
-
return value;
|
|
20
|
-
};
|
|
21
|
-
var __callDispose = (stack, error, hasError) => {
|
|
22
|
-
var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
|
|
23
|
-
return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
|
|
24
|
-
};
|
|
25
|
-
var fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e);
|
|
26
|
-
var next = (it) => {
|
|
27
|
-
while (it = stack.pop()) {
|
|
28
|
-
try {
|
|
29
|
-
var result = it[1] && it[1].call(it[2]);
|
|
30
|
-
if (it[0])
|
|
31
|
-
return Promise.resolve(result).then(next, (e) => (fail(e), next()));
|
|
32
|
-
} catch (e) {
|
|
33
|
-
fail(e);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (hasError)
|
|
37
|
-
throw error;
|
|
38
|
-
};
|
|
39
|
-
return next();
|
|
40
|
-
};
|
|
41
|
-
import { vitePluginDb } from "./vite-plugin-db.js";
|
|
42
|
-
import { vitePluginInjectEnvTs } from "./vite-plugin-inject-env-ts.js";
|
|
43
|
-
import { typegen } from "./typegen.js";
|
|
44
1
|
import { existsSync } from "fs";
|
|
45
|
-
import { mkdir, rm, writeFile } from "fs/promises";
|
|
46
|
-
import { DB_PATH } from "../consts.js";
|
|
47
|
-
import { createLocalDatabaseClient } from "../../runtime/db-client.js";
|
|
48
|
-
import { astroConfigWithDbSchema } from "../types.js";
|
|
49
|
-
import {} from "../utils.js";
|
|
50
|
-
import { STUDIO_CONFIG_MISSING_WRITABLE_TABLE_ERROR, UNSAFE_WRITABLE_WARNING } from "../errors.js";
|
|
51
|
-
import { errorMap } from "./error-map.js";
|
|
52
2
|
import { dirname } from "path";
|
|
53
3
|
import { fileURLToPath } from "url";
|
|
4
|
+
import { mkdir, rm, writeFile } from "fs/promises";
|
|
54
5
|
import { blue, yellow } from "kleur/colors";
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
6
|
+
import { CONFIG_FILE_NAMES, DB_PATH } from "../consts.js";
|
|
7
|
+
import { loadDbConfigFile } from "../load-file.js";
|
|
57
8
|
import { getManagedAppTokenOrExit } from "../tokens.js";
|
|
9
|
+
import { dbConfigSchema } from "../types.js";
|
|
10
|
+
import { getDbDirectoryUrl } from "../utils.js";
|
|
11
|
+
import { errorMap } from "./error-map.js";
|
|
12
|
+
import { fileURLIntegration } from "./file-url.js";
|
|
13
|
+
import { typegen } from "./typegen.js";
|
|
14
|
+
import { vitePluginDb } from "./vite-plugin-db.js";
|
|
15
|
+
import { vitePluginInjectEnvTs } from "./vite-plugin-inject-env-ts.js";
|
|
58
16
|
function astroDBIntegration() {
|
|
59
|
-
let
|
|
17
|
+
let connectToStudio = false;
|
|
18
|
+
let configFileDependencies = [];
|
|
19
|
+
let root;
|
|
60
20
|
let appToken;
|
|
61
|
-
let
|
|
62
|
-
|
|
63
|
-
|
|
21
|
+
let dbConfig;
|
|
22
|
+
let tables = {
|
|
23
|
+
get() {
|
|
24
|
+
throw new Error("[astro:db] INTERNAL Tables not loaded yet");
|
|
64
25
|
}
|
|
65
26
|
};
|
|
66
27
|
let command;
|
|
@@ -69,24 +30,26 @@ function astroDBIntegration() {
|
|
|
69
30
|
hooks: {
|
|
70
31
|
"astro:config:setup": async ({ updateConfig, config, command: _command, logger }) => {
|
|
71
32
|
command = _command;
|
|
72
|
-
|
|
33
|
+
root = config.root;
|
|
34
|
+
if (command === "preview")
|
|
73
35
|
return;
|
|
74
36
|
let dbPlugin = void 0;
|
|
75
|
-
|
|
76
|
-
if (
|
|
37
|
+
connectToStudio = command === "build";
|
|
38
|
+
if (connectToStudio) {
|
|
77
39
|
appToken = await getManagedAppTokenOrExit();
|
|
78
|
-
connectedToRemote = true;
|
|
79
40
|
dbPlugin = vitePluginDb({
|
|
80
|
-
connectToStudio
|
|
41
|
+
connectToStudio,
|
|
81
42
|
appToken: appToken.token,
|
|
82
|
-
|
|
83
|
-
root: config.root
|
|
43
|
+
tables,
|
|
44
|
+
root: config.root,
|
|
45
|
+
srcDir: config.srcDir
|
|
84
46
|
});
|
|
85
47
|
} else {
|
|
86
48
|
dbPlugin = vitePluginDb({
|
|
87
49
|
connectToStudio: false,
|
|
88
|
-
|
|
89
|
-
root: config.root
|
|
50
|
+
tables,
|
|
51
|
+
root: config.root,
|
|
52
|
+
srcDir: config.srcDir
|
|
90
53
|
});
|
|
91
54
|
}
|
|
92
55
|
updateConfig({
|
|
@@ -96,63 +59,44 @@ function astroDBIntegration() {
|
|
|
96
59
|
}
|
|
97
60
|
});
|
|
98
61
|
},
|
|
99
|
-
"astro:config:done": async ({ config
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
} else if (unsafeWritable && foundWritableCollection) {
|
|
111
|
-
logger.warn(UNSAFE_WRITABLE_WARNING);
|
|
112
|
-
}
|
|
113
|
-
if (!connectedToRemote) {
|
|
114
|
-
var _stack = [];
|
|
115
|
-
try {
|
|
116
|
-
const dbUrl = new URL(DB_PATH, config.root);
|
|
117
|
-
if (existsSync(dbUrl)) {
|
|
118
|
-
await rm(dbUrl);
|
|
119
|
-
}
|
|
120
|
-
await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
|
|
121
|
-
await writeFile(dbUrl, "");
|
|
122
|
-
const db = __using(_stack, await createLocalDatabaseClient({
|
|
123
|
-
tables,
|
|
124
|
-
dbUrl: dbUrl.toString(),
|
|
125
|
-
seeding: true
|
|
126
|
-
}));
|
|
127
|
-
await recreateTables({ db, tables });
|
|
128
|
-
if (configWithDb.db?.data) {
|
|
129
|
-
await seedData({
|
|
130
|
-
db,
|
|
131
|
-
data: configWithDb.db.data,
|
|
132
|
-
logger,
|
|
133
|
-
mode: command === "dev" ? "dev" : "build"
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
logger.debug("Database setup complete.");
|
|
137
|
-
} catch (_) {
|
|
138
|
-
var _error = _, _hasError = true;
|
|
139
|
-
} finally {
|
|
140
|
-
__callDispose(_stack, _error, _hasError);
|
|
62
|
+
"astro:config:done": async ({ config }) => {
|
|
63
|
+
const { mod, dependencies } = await loadDbConfigFile(config.root);
|
|
64
|
+
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) {
|
|
70
|
+
const dbUrl = new URL(DB_PATH, config.root);
|
|
71
|
+
if (existsSync(dbUrl)) {
|
|
72
|
+
await rm(dbUrl);
|
|
141
73
|
}
|
|
74
|
+
await mkdir(dirname(fileURLToPath(dbUrl)), { recursive: true });
|
|
75
|
+
await writeFile(dbUrl, "");
|
|
142
76
|
}
|
|
143
|
-
await typegen({ tables, root: config.root });
|
|
77
|
+
await typegen({ tables: tables.get() ?? {}, root: config.root });
|
|
144
78
|
},
|
|
145
79
|
"astro:server:start": async ({ logger }) => {
|
|
146
80
|
setTimeout(() => {
|
|
147
81
|
logger.info(
|
|
148
|
-
|
|
82
|
+
connectToStudio ? "Connected to remote database." : "New local database created."
|
|
149
83
|
);
|
|
150
84
|
}, 100);
|
|
151
85
|
},
|
|
86
|
+
"astro:server:setup": async ({ server }) => {
|
|
87
|
+
const filesToWatch = [
|
|
88
|
+
...CONFIG_FILE_NAMES.map((c) => new URL(c, getDbDirectoryUrl(root))),
|
|
89
|
+
...configFileDependencies.map((c) => new URL(c, root))
|
|
90
|
+
];
|
|
91
|
+
server.watcher.on("all", (event, relativeEntry) => {
|
|
92
|
+
const entry = new URL(relativeEntry, root);
|
|
93
|
+
if (filesToWatch.some((f) => entry.href === f.href)) {
|
|
94
|
+
server.restart();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
},
|
|
152
98
|
"astro:build:start": async ({ logger }) => {
|
|
153
|
-
logger.info(
|
|
154
|
-
"database: " + (connectedToRemote ? yellow("remote") : blue("local database."))
|
|
155
|
-
);
|
|
99
|
+
logger.info("database: " + (connectToStudio ? yellow("remote") : blue("local database.")));
|
|
156
100
|
},
|
|
157
101
|
"astro:build:done": async ({}) => {
|
|
158
102
|
await appToken?.destroy();
|
|
@@ -18,21 +18,11 @@ ${Object.entries(tables).map(([name, collection]) => generateTableType(name, col
|
|
|
18
18
|
await writeFile(new URL(DB_TYPES_FILE, dotAstroDir), content);
|
|
19
19
|
}
|
|
20
20
|
function generateTableType(name, collection) {
|
|
21
|
+
const sanitizedColumnsList = Object.entries(collection.columns).filter(([key, val]) => !val.schema.deprecated);
|
|
22
|
+
const sanitizedColumns = Object.fromEntries(sanitizedColumnsList);
|
|
21
23
|
let tableType = ` export const ${name}: import(${RUNTIME_IMPORT}).Table<
|
|
22
24
|
${JSON.stringify(name)},
|
|
23
|
-
${JSON.stringify(
|
|
24
|
-
Object.fromEntries(
|
|
25
|
-
Object.entries(collection.columns).map(([columnName, column]) => [
|
|
26
|
-
columnName,
|
|
27
|
-
{
|
|
28
|
-
// Only select columns Drizzle needs for inference
|
|
29
|
-
type: column.type,
|
|
30
|
-
optional: column.schema.optional,
|
|
31
|
-
default: column.schema.default
|
|
32
|
-
}
|
|
33
|
-
])
|
|
34
|
-
)
|
|
35
|
-
)}
|
|
25
|
+
${JSON.stringify(sanitizedColumns)}
|
|
36
26
|
>;`;
|
|
37
27
|
return tableType;
|
|
38
28
|
}
|